【问题标题】:C++ How do I prevent Memory Protection Violation?C++ 如何防止内存保护违规?
【发布时间】:2023-03-08 14:53:01
【问题描述】:

我遇到了内存违规问题,如果达到else if(argc == 2)

我正在尝试编写一个没有类似错误的漂亮脚本,其他任何东西都像一个魅力......

这是一个代码片段:

//...
// 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
        }
//...

编辑:除了 argc 和 argv[] 值程序没有分配任何变量

编辑 2.:程序由 2 个参数动作和 3 个参数动作构成,就像我发布的代码中提到的那样。

【问题讨论】:

  • 您在尝试访问第三个参数后检查是否有 3 个参数。首先验证参数的数量是否正确,然后尝试使用它们。
  • 是的,但我也有 2 个参数操作,所以我也需要它们
  • @Yksisarvinen 哦,我想我明白你的意思了。如果存在第三个参数,我应该在正确的第二次访问后检查吗?
  • 我的意思是你应该重新订购你的ifs。首先检查if(argc == 2)(或&lt; 3,会更安全),然后检查else if(argc &gt; 3),如果参数是"on" 或"off",最后检查else 子句。这样,当没有足够的参数时,您将不会尝试访问该参数。
  • 我怀疑您没有考虑时间因素,而是期望选择“最佳”条件,而不管它们的文本顺序如何。 (这并非不合理,但这也不是事情的运作方式。)

标签: c++ linux serial-port command-line-arguments argv


【解决方案1】:

如果这种情况

else if(argc == 2)

计算为真则意味着argv[argc] 等于nullptr。因此,在这种情况下,例如在调用strcmp 时使用表达式argv[2](即空指针)会导致未定义的行为。索引的有效范围是[0, 1]。

来自 C++ 14 标准(3.6.1 主函数)

  1. ...如果 argc 不为零,则应在 argv[0] 中提供这些参数 通过 argv[argc-1] 作为指向 以 null 结尾的多字节字符串 (ntmbs s) (17.5.2.1.4.2) 和 argv[0] 应该是指向 ntmbs 的初始字符的指针 表示用于调用程序的名称或“”。的价值 argc 应为非负数。 argv[argc]的值为0。

【讨论】:

  • 那么现在我发布的答案是否正确?如果有,有什么区别?
  • @spyx33 如果 argc 等于 3,则索引的有效范围是 [0, 2],您可以使用表达式 argv[2]
  • 但是我不明白的是,如果我(有问题的代码)只检查参数数量是否错误,例如program arg1 argc=2 而不是 program arg1 arg2 argc=3
  • @spyx33 您正在使用空指针 tp 在调用 strcmp 时访问内存。那就是你的程序试图读取地址 0 处的内存。
  • 哦,现在我明白了,所以我在第一个 if 语句中遇到错误,因为它试图读取不存在的值,甚至没有达到应该安全退出脚本的语句。非常感谢,这对我帮助很大!
【解决方案2】:

我遵循了@Yksisarvinen 的建议并重新排序了代码,现在它可以完美运行:

//...
        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
        }
//...

【讨论】:

    猜你喜欢
    • 2021-07-18
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    • 2014-05-17
    • 2012-04-13
    • 2018-01-18
    • 2012-06-14
    • 2010-11-29
    相关资源
    最近更新 更多