1

I have a problem with memory violation problem that occurs if reach else if(argc == 2)

I'm trying to have a nice written script with no errors like that, anything else works like a charm...

Here's a code fragment:

//...
// POWER ON
        if(strcmp(argv[2], "on") == 0)
        {
            // GPIO On
            pin_on();
            // Open the serial port READ-WRITE
            int serial_port = open("/dev/ttyS5", O_RDWR);
            // Load serial port settings
            settings(serial_port);
            // POWER ON Message
            unsigned char msg[] = { '\x2A', '\x20', '\x30', '\x20',
                                    '\x49', '\x52', '\x20', '\x30',
                                    '\x30', '\x31', '\x0D' };
            // Send message to device
            write(serial_port, msg, sizeof(msg));
            // Time for device to process
            std::system("sleep 0.25");
            // Close the serial port
            close(serial_port);
            // GPIO Off
            pin_off();
            return 0;   // success
        }
        // POWER OFF
        else if(strcmp(argv[2], "off") == 0)
        {
            // GPIO On
            pin_on();
            // Open the serial port READ-WRITE
            int serial_port = open("/dev/ttyS5", O_RDWR);
            // Load serial port settings
            settings(serial_port);
            // POWER OFF Message
            unsigned char msg[] = { '\x2A', '\x20', '\x30', '\x20',
                                    '\x49', '\x52', '\x20', '\x30',
                                    '\x30', '\x32', '\x0D' };
            // Send message to device
            write(serial_port, msg, sizeof(msg));
            // Time for device to process
            std::system("sleep 0.25");
            // Close the serial port
            close(serial_port);
            // GPIO Off
            pin_off();
            return 0;   // success
        }
        else if(argc == 2)
        {
            std::cout << "No argument passed!" << std::endl;
            std::cout << "Pattern: acer power <on/off>" << std::endl;
            return 1;   // failure
        }
        else if(argc > 3)
        {
            std::cout << "Too many arguments passed!" << std::endl;
            std::cout << "Pattern: acer power <on/off>" << std::endl;
            return 1;   // failure
        }
        else
        {
            std::cout << "Wrong argument! Passed: " << std::string(argv[2]) << std::endl;
            std::cout << "Pattern: acer power <on/off>" << std::endl;
            return 1;   // failure
        }
//...

Edit: Besides argc and argv[] values program doesn't asign any variables

Edit 2.: Program is constructed of 2 argument actions and 3 arguments actions like this one mentioned it code I posted.

5
  • 5
    You check if there are 3 arguments after you try to access 3rd argument. First verify if the number of arguments is correct, then try to use them. Commented Jun 8, 2021 at 10:12
  • Yes but I also have a 2 argument actions so I also need them Commented Jun 8, 2021 at 10:14
  • @Yksisarvinen Oh I think I get what you meant. Should I check after correct 2nd access if 3rd argument is present? Commented Jun 8, 2021 at 10:17
  • 1
    I mean you should reorder your ifs. First check if(argc == 2) (or < 3, would be safer), then else if(argc > 3), then if the argument is "on" or "off" and finally your else clause. This way, when there is not enough arguments, you will not try to access that argument. Commented Jun 8, 2021 at 10:22
  • I suspect that you're not considering the element of time, but expecting the "best" condition to be chosen regardless of their textual ordering. (Which isn't unreasonable, but it's also not how things work.)
    – molbdnilo
    Commented Jun 8, 2021 at 10:55

2 Answers 2

2

If this condition

else if(argc == 2)

evaluates to true then it means that argv[argc] is equal to nullptr. So using the expression argv[2] (that is a null pointer) in this case for example in a call of strcmp results in undefined behavior. The valid range of indices is [0, 1].

From the C++ 14 Standard (3.6.1 Main function)

  1. ...If argc is nonzero these arguments shall be supplied in argv[0] through argv[argc-1] as pointers to the initial characters of null-terminated multibyte strings (ntmbs s) (17.5.2.1.4.2) and argv[0] shall be the pointer to the initial character of a ntmbs that represents the name used to invoke the program or "". The value of argc shall be non-negative. The value of argv[argc] shall be 0.
5
  • So now in the answer I posted is it correct? If so, what's the diffrence? Commented Jun 8, 2021 at 10:32
  • @spyx33 If argc is equal to 3 then the valid range of indices is [0, 2] and you may use the expression argv[2] Commented Jun 8, 2021 at 10:34
  • But what I don't get is why it return memory protection validation if I (the code in question) only check if the number of arguments is wrong like program arg1 argc=2 and not program arg1 arg2 argc=3 Commented Jun 8, 2021 at 10:38
  • 1
    @spyx33 You are using a null pointer tp access a memory in calls of strcmp. That is your program tries to read the memory at the address 0. Commented Jun 8, 2021 at 10:39
  • Oh, now I understand so I get error with first if statement because it tries to read no existing value and doesn't even reach statement that should safely quit the script. Thank you so much, that helped me a lot! Commented Jun 8, 2021 at 10:42
0

I followed @Yksisarvinen advice and reorder the code and now it works flawless:

//...
        if(argc == 3)
        {
            // POWER ON
            if(strcmp(argv[2], "on") == 0)
            {
                // GPIO On
                pin_on();
                // Open the serial port READ-WRITE
                int serial_port = open("/dev/ttyS5", O_RDWR);
                // Load serial port settings
                settings(serial_port);
                // POWER ON Message
                unsigned char msg[] = { '\x2A', '\x20', '\x30', '\x20',
                                        '\x49', '\x52', '\x20', '\x30',
                                        '\x30', '\x31', '\x0D' };
                // Send message to device
                write(serial_port, msg, sizeof(msg));
                // Time for device to process
                std::system("sleep 0.25");
                // Close the serial port
                close(serial_port);
                // GPIO Off
                pin_off();
                return 0;   // success
            }
            // POWER OFF
            else if(strcmp(argv[2], "off") == 0)
            {
                // GPIO On
                pin_on();
                // Open the serial port READ-WRITE
                int serial_port = open("/dev/ttyS5", O_RDWR);
                // Load serial port settings
                settings(serial_port);
                // POWER OFF Message
                unsigned char msg[] = { '\x2A', '\x20', '\x30', '\x20',
                                        '\x49', '\x52', '\x20', '\x30',
                                        '\x30', '\x32', '\x0D' };
                // Send message to device
                write(serial_port, msg, sizeof(msg));
                // Time for device to process
                std::system("sleep 0.25");
                // Close the serial port
                close(serial_port);
                // GPIO Off
                pin_off();
                return 0;   // success
            }
            else
            {
                std::cout << "Wrong argument! Passed: " << std::string(argv[2]) << std::endl;
                std::cout << "Pattern: acer power <on/off>" << std::endl;
                return 1;   // failure
            }
        }
        else if(argc == 2)
        {
            std::cout << "No argument passed!" << std::endl;
            std::cout << "Pattern: acer power <on/off>" << std::endl;
            return 1;   // failure
        }
        else
        {
            std::cout << "Too many arguments passed!" << std::endl;
            std::cout << "Pattern: acer power <on/off>" << std::endl;
            return 1;   // failure
        }
//...

Not the answer you're looking for? Browse other questions tagged or ask your own question.