简体   繁体   English

fprintf在特定字符串上失败,而外壳函数使用它时没有崩溃

[英]fprintf fails on specific string while shell functions use it with no crash

The short version: I have a C++ code that uses a C call to fprintf(stdout, some_cpp_str.c_str()) and crashes during it. 简短的版本:我有一个C ++代码,该代码使用C调用fprintf(stdout, some_cpp_str.c_str())并在崩溃期间崩溃。 The first 4 calls are fine, only the 5th crashes, and I have no idea why (suspecting unreadable char inside the string) . 前4个调用很好,只有第5个崩溃,我也不知道为什么(怀疑字符串中的char不可读) The 1st code I posted was mostly C, so I posted another one, with only C++ except for the fprintf (code added at the bottom of the question). 我发布的第一个代码主要是C,所以我发布了另一个代码,除了fprintf (问题底部添加的代码)外,只有C ++。 The crashes occur (consistently) on an embedded device. 崩溃(一致)发生在嵌入式设备上。 On my own PC the code runs fine 在我自己的PC上,代码运行正常


The long version: 长版:

I have a code that reads lines from text, and pushes them into a string vector. 我有一个代码,可从文本中读取行,并将其推入字符串向量中。 TO check my progress, I also fprintf them to the screen after the vector is populated: 要检查我的进度,在填充矢量之后,我还将它们fprintf到屏幕上:

int main(){
    char    err_msg[256], * line = NULL, *in_file = "...", *keyword = "blah";
    size_t  len = 0;
        ssize_t num_bytes_read;
    int i = 1;
    std::vector<std::string> lines_vector;

    FILE * fp = fopen(in_file, "r");
    if (!fp) {
        fprintf(stdout,"can't open file %s for reading\n", in_file);
        goto EXIT;
    }

    while ((num_bytes_read = getline(&line, &len, fp)) != -1) {
        /* if found keyword inside line */
        if (strstr(line, keyword)) {
            /* add 3 lines (entry heading, entry body, newline)*/
            lines_vector.push_back(std::string(line));
            for(int lines_to_copy = 2; lines_to_copy > 0; lines_to_copy--) {
                if((num_bytes_read = getline(&line, &len, fp)) == -1) {
                    fprintf(stdout,"can't read line from %s\n", in_file);
                    goto EXIT;
                }
                lines_vector.push_back(std::string(line));
            }
        }
    }
    fprintf(stdout,"finished reading from file\n");

EXIT:
    fclose(fp);
    free(line);

    for (std::vector<std::string>::iterator it = lines_vector.begin() ; it != lines_vector.end(); ++it, ++i) {
        fprintf(stdout, "%d)", i);
        fprintf(stdout, "%s", (*it).c_str());
    }
    return 0;
}

This works fine on my VM, but I also run it on an embedded device, where it always crashes on a specific line. 这在我的VM上可以正常工作,但我也可以在嵌入式设备上运行它,该设备总是在特定的行上崩溃。 The line is: 该行是:

certificates local generate name localcert common-name sf country(region) AB auto-regenerate-days 12 auto-regenerate-days-warning 11 e-mail X@Y.com locality(city) Z organization Q organization-unit T scep-password-string 57E6CA35452E72E4D1BC4518260ABFC7 scep-url http://0.0.0.0/X/Y/ state(province) s

I don't think there is a problem in the line itself (as it doesn't crash on my VM). 我不认为生产线本身有问题(因为它不会在我的VM上崩溃)。 When trying to print it to a file instead of to the screen, it doesn't crash: 尝试将其打印到文件而不是屏幕上时,它不会崩溃:

for (std::vector<std::string>::iterator it = lines_vector.begin(); it != lines_vector.end(); ++it){
    sprintf(tmp, "echo \"%s\" >> /X/Y/Z.txt", (*it).c_str());
    OS_run(tmp);  // run this command on sh shell
}

Since it crashes only on my embedded and not my VM, I thought the file is somehow corrupted. 由于它仅在我的嵌入式系统而不是我的VM上崩溃,因此我认为该文件已损坏。 Could it be that the string has an invalid char inside that crashes fprintf , but not echo ? 可能是字符串内部包含无效char导致fprintf崩溃,但没有echo


I tried translating this code into proper C++, but I still get a crash in the middle of the last string. 我尝试将这段代码转换为正确的C ++,但是最后一个字符串的中间仍然出现崩溃。 I know mixing C/C++ is not good, but shouldn't c_str() be a proper interface between std::string and char * (which fprintf expects)? 我知道混合C / C ++不好,但是c_str()不应该是std::string和char *( fprintf期望的)之间的适当接口吗?

If not this, then what could possibly crash during the fprintf ? 如果不是这样,那么在fprintf期间可能会崩溃吗?

int main()
{
    std::vector<std::string> lines_vector;
    std::ifstream infile(in_file);
    std::string line;
    int counter = 1;

    while (std::getline(infile, line))  {
        if (line.find(keyword, 0) != std::string::npos) {
            lines_vector.push_back(line);
            for(int lines_to_copy = 2; lines_to_copy > 0; lines_to_copy--)  {
                std::getline(infile, line);
                lines_vector.push_back(line);
            }
        }
    }

    for (std::vector<std::string>::iterator it = lines_vector.begin(); it != lines_vector.end(); ++it){
        fprintf(stdout, "%d)%s", counter++, (*it).c_str());
    }
}

On an embedded device, you can expect that dynamic memory allocation fail. 在嵌入式设备上,可以预期动态内存分配失败。 That means that you absolutely must control all possible allocations (you should anyway even on non embedded device, but the crash risk is much lower...). 这意味着您绝对必须控制所有可能的分配(无论如何,即使在非嵌入式设备上也应如此,但是崩溃风险要低得多……)。 You really should have: 您确实应该具有:

while ((num_bytes_read = getline(&line, &len, fp)) != -1) {
    ...
}
if (line == NULL) {
    perror("getline could not allocate buffer");
}

This will not fix anything, but at least you will know what happens. 这不会解决任何问题,但至少您会知道会发生什么。


I have respected your coding style here, making heavy use of the C library and also using goto . 我在这里尊重您的编码风格,充分利用了C库以及goto But I must advise you not to do that in C++ programs. 但是我必须建议您不要在C ++程序中这样做。

C library used to be included in C++ standard library because early C++ implementations were lacking too many functionalities. C库曾经包含在C ++标准库中,因为早期的C ++实现缺少太多的功能。 In modern C++ goto is to be banned, as are all raw C strings and C io functions (except in very special use cases). 在现代C ++中,所有原始C字符串和C io函数(在非常特殊的用例中除外)都将被禁止使用goto And C++ come with a version of getline (in header <string> ) that directly fills a std::string . C ++附带了getline版本(在标头<string> ),该版本直接填充std::string You really should try to avoid C construct if learning C++. 如果学习C ++,您确实应该避免使用C构造。


Per Ben Voigt's comment, there are correct use case to use old style C library if you want to avoid dynamic allocation. 根据Ben Voigt的评论,如果要避免动态分配,则有使用旧样式C库的正确用例。 But in that case, you should also avoid std::string and std::vector 但是在这种情况下,您还应该避免使用std::stringstd::vector

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM