0

所以我有这个函数,它将获取一个字符串对列表并生成一个 COMDLG_FILTERSPEC 数组。对是这样的:第一个 ="All Types"第二个 ="*.*"

该函数有效,但是我得到缓冲区溢出,如下所示:

在此处输入图像描述

我也收到了这条好消息,告诉我我会遇到缓冲区溢出 在此处输入图像描述

我不知道如何解决这个问题或为什么它会超支。任何人都可以帮忙吗?

这是代码:

COMDLG_FILTERSPEC * CreateFILTERSPEC(std::list<std::pair<std::wstring, std::wstring>> _filters) {

    //TODO: Causes memory leak on deletion. Fix it.

    COMDLG_FILTERSPEC* filterSpecs = new COMDLG_FILTERSPEC[_filters.size()];

    int i = 0;
    for (std::pair<std::wstring, std::wstring> filter : _filters) {


        PWSTR f1_p = new wchar_t[filter.first.length()];
        filter.first.copy(f1_p, filter.first.length());

        PWSTR f2_p = new wchar_t[filter.second.length()];
        filter.second.copy(f2_p, filter.second.length());

        COMDLG_FILTERSPEC fs = { f1_p, f2_p };

        filterSpecs[i] = fs;
        i++;
    }

    return filterSpecs;

}

任何帮助表示赞赏,谢谢。

4

1 回答 1

0

问题不是由于缓冲区溢出,而是您根本没有对wchar[]要添加到过滤器的字符串进行空终止。

根据cppreference.com 上的std::basic_string::copy()文档:

将子字符串复制[pos, pos+count)到 指向的字符串dest。如果请求的子字符串持续到字符串的末尾,或者如果count == npos,则复制的子字符串是[pos, size())结果字符串不是以空值结尾的。

因此,您需要将这些空终止符添加到您的字符串中,例如:

COMDLG_FILTERSPEC* CreateFILTERSPEC(const std::list<std::pair<std::wstring, std::wstring>> &_filters) {

    COMDLG_FILTERSPEC* filterSpecs = new COMDLG_FILTERSPEC[_filters.size()];
    COMDLG_FILTERSPEC* filterSpec = filterSpecs;

    for (const auto &filter : _filters) {

        PWSTR f1_p = new wchar_t[filter.first.length() + 1]; // <-- note the +1 !
        filter.first.copy(f1_p, filter.first.length());
        f1_p[filter.first.length()] = L'\0'; // <-- add this !

        PWSTR f2_p = new wchar_t[filter.second.length() + 1]; // <-- note the +1 !
        filter.second.copy(f2_p, filter.second.length());
        f2_p[filter.second.length()] = L'\0'; // <-- add this !

        filterSpec->pszName = f1_p;
        filterSpec->pszSpec = f2_p;
        ++filterSpec;
    }

    return filterSpecs;
}
COMDLG_FILTERSPEC *filterSpecs = CreateFILTERSPEC(filters);

// use filterSpecs as needed ...

for(int i = 0; i < filters.size(); ++i) {
    delete[] filterSpecs[i].pszName;
    delete[] filterSpecs[i].pszSpec;
};
delete[] filterSpecs;

或者,您可以将所有new[]'ed 内存合并到一个分配中以便于清理,例如:

COMDLG_FILTERSPEC* CreateFILTERSPEC(const std::list<std::pair<std::wstring, std::wstring>> &_filters) {

    size_t size = sizeof(COMDLG_FILTERSPEC) * _filters.size();
    for (const auto &filter : _filters) {
        size += (filter.first.length() + filter.second.length() + 2);
    }

    COMDLG_FILTERSPEC* filterSpecs = reinterpret_cast<COMDLG_FILTERSPEC*>(new BYTE[size]);
    COMDLG_FILTERSPEC* filterSpec = filterSpecs;
    wchar_t *strData = reinterpret_cast<wchar_t*>(filterSpecs + _filters.size());

    for (const auto &filter : _filters) {

        filterSpec->pszName = strData;
        filter.first.copy(strData, filter.first.length());
        strData += filter.first.length();
        *strData++ = L'\0';

        filterSpec->pszSpec = strData;
        filter.second.copy(strData, filter.second.length());
        strData += filter.second.length();
        *strData++ = L'\0';

        ++filterSpec;
    }

    return filterSpecs;
}
COMDLG_FILTERSPEC *filterSpecs = CreateFILTERSPEC(filters);

// use filterSpecs as needed ...

delete[] reinterpret_cast<BYTE*>(filterSpecs);

但是,如果 的内容std::list将持续超过 的生命周期COMDLG_FILTERSPEC,那么您根本不需要new[]任何内存来存储字符串,只需std::wstring按原样使用现有内存,例如:

COMDLG_FILTERSPEC * CreateFILTERSPEC(const std::list<std::pair<std::wstring, std::wstring>> &_filters) {

    COMDLG_FILTERSPEC* filterSpecs = new COMDLG_FILTERSPEC[_filters.size()];
    COMDLG_FILTERSPEC* filterSpec = filterSpecs;

    for (const auto &filter : _filters) {
        filterSpec->pszName = filter.first.c_str();
        filterSpec->pszSpec = filter.second.c_str();
        ++filterSpec;
    }

    return filterSpecs;
}
COMDLG_FILTERSPEC *filterSpecs = CreateFILTERSPEC(filters);

// use filterSpecs as needed ...

delete[] filterSpecs;

在这种情况下,您应该考虑返回 astd::unique_ptr<COMDLG_FILTERSPEC[]>而不是原始COMDLG_FILTERSPEC*指针,例如:

std::unique_ptr<COMDLG_FILTERSPEC[]> CreateFILTERSPEC(const std::list<std::pair<std::wstring, std::wstring>> &_filters) {

    auto filterSpecs = std::make_unique<COMDLG_FILTERSPEC[]>(_filters.size());
    COMDLG_FILTERSPEC* filterSpec = filterSpecs.get();

    for (const auto &filter : _filters) {
        filterSpec->pszName = filter.first.c_str();
        filterSpec->pszSpec = filter.second.c_str();
        ++filterSpec;
    }

    return filterSpecs;
}
auto filterSpecs = CreateFILTERSPEC(filters);

// use filterSpecs.get() as needed ...

// the COMDLG_FILTERSPEC memory is freed automatically when
// filterSpecs goes out of scope...

或者,返回 a std::vector,例如:

std::vector<COMDLG_FILTERSPEC> CreateFILTERSPEC(const std::list<std::pair<std::wstring, std::wstring>> &_filters) {

    std::vector<COMDLG_FILTERSPEC> filterSpecs(_filters.size());
    COMDLG_FILTERSPEC* filterSpec = filterSpecs.data();

    for (const auto &filter : _filters) {
        filterSpec->pszName = filter.first.c_str();
        filterSpec->pszSpec = filter.second.c_str();
        ++filterSpec;
    }

    return filterSpecs;
}
auto filterSpecs = CreateFILTERSPEC(filters);

// use filterSpecs.data() as needed ...

// the COMDLG_FILTERSPEC memory is freed automatically when
// filterSpecs goes out of scope...
于 2021-11-30T22:54:52.980 回答