不理解 gSOAP 序列化期间的错误

发布于 2025-01-04 13:41:14 字数 2113 浏览 0 评论 0原文

在 Windows、C# 和托管 C++ 上使用 gSoap 2.7.17。

我有 (gSOAP) 类描述文件数组:

class ns__ContainerFile
{
public:
    xsd__long           fileId;
    xsd__string         fileName;
};

class ContainerFileArray
{
public:
    ns__ContainerFile         *__ptr;
    int                       __size;
};

class ns__Container
{
public:
    xsd__long           containerId     0:1 = 0;
    xsd__string         name            0:1 = "";
    xsd__string         description     0:1 = "";
    ContainerFileArray* files           0:1 = NULL;
};

在托管 c++ 中,我分配返回数组:

ContainerFileArray gSoapArray;
gSoapArray.__size = managedArray->Length;
gSoapArray.__ptr = (ns__ContainerFile*) soap_malloc(soap, sizeof(ns__ContainerFile) * gSoapArray.__size);

上面的代码是名为 ConvertArray 的方法的一部分,该方法的调用方式如下:

ns__Container unManaged;
*unManaged.files = ConvertArray(soap, managed->files->ToArray());

问题是,虽然 ConvertArray 似乎运行正常(我可以看到数据元素似乎在 malloc'ed 内存中正确填充),当我们包装 Web 服务请求时,我在序列化步骤中遇到了访问冲突(即:我们的 C++ 代码已发出 SOAP_OK 返回值,并且逻辑又回到了自动生成的 gSOAP 代码)。

当处理简单类型的数组(整数、长整型等)时,整个过程工作得很好,但处理更复杂的类型(类等)时,整个过程就会崩溃。

如果在 ConvertArray 方法中,我替换第 3 行:

gSoapArray.__ptr = soap_new_ns__ContainerFile(soap, gSoapArray.__size);

来分配内存,则它可以正常工作。

所以,我不确定我是否理解为什么。在第一种情况下,我使用soap_malloc 分配一块内存块,该内存块的大小是ContainerFile 类的大小乘以托管数组中的许多元素。在第二种情况下,归结为使用soap_new 来做同样的事情。如果分配的内存全部由 gsoap 管理并且在其他方​​面相同(据我所知),为什么在序列化过程中,soap_malloc'ed 版本会失败?

使用 Visual Studio,我可以看到它在以下生成的代码中失败:

void ContainerFileArray::soap_serialize(struct soap *soap) const
{
    if (this->__ptr && !soap_array_reference(soap, this, (struct soap_array*)&this->__ptr, 1, SOAP_TYPE_ContainerFileArray))
        for (int i = 0; i < this->__size; i++)
        {    soap_embedded(soap, this->__ptr + i, SOAP_TYPE_IDCXDService__ContainerFile);
            this->__ptr[i].soap_serialize(soap);
        }
}

指示器位于突出显示的行上,但我怀疑它在soap_embedded 调用中失败。我还应该注意到,它在 malloc 块中的第一个元素上失败(即:当 i == 0 时)。

Working with gSoap 2.7.17 on Windows, C# and managed C++.

I have (gSOAP) classes describing an array of files:

class ns__ContainerFile
{
public:
    xsd__long           fileId;
    xsd__string         fileName;
};

class ContainerFileArray
{
public:
    ns__ContainerFile         *__ptr;
    int                       __size;
};

class ns__Container
{
public:
    xsd__long           containerId     0:1 = 0;
    xsd__string         name            0:1 = "";
    xsd__string         description     0:1 = "";
    ContainerFileArray* files           0:1 = NULL;
};

In managed c++, I allocate my return array:

ContainerFileArray gSoapArray;
gSoapArray.__size = managedArray->Length;
gSoapArray.__ptr = (ns__ContainerFile*) soap_malloc(soap, sizeof(ns__ContainerFile) * gSoapArray.__size);

The code above is part of a method named ConvertArray, which is called thus:

ns__Container unManaged;
*unManaged.files = ConvertArray(soap, managed->files->ToArray());

Problem is, while the ConvertArray appears to run properly (I can see the data elements seemingly properly filled in within the malloc'ed memory), I'm getting access violations during the serialization step when we are wrapping up the web service request (ie: our C++ code has issued the SOAP_OK return value and the logic has returned to the auto-generated gSOAP code).

This whole process works just fine when dealing with arrays of simple types - ints, longs, etc but blows up with more complex types - classes and the like.

If, in the ConvertArray method, I substitute on line 3:

gSoapArray.__ptr = soap_new_ns__ContainerFile(soap, gSoapArray.__size);

to allocate the memory, it works fine.

So, I'm not sure I understand why. In the first case, I'm using soap_malloc to allocate a block of memory that is the size of the ContainerFile class times however many elements are in the managed array. In the second case, it boils down to using soap_new to do the same thing. If the allocated memory is all managed by gsoap and is otherwise the same (as far as I can tell), why should the soap_malloc'ed version fail during serialization?

Using Visual Studio, I can see that it fails in the following generated code:

void ContainerFileArray::soap_serialize(struct soap *soap) const
{
    if (this->__ptr && !soap_array_reference(soap, this, (struct soap_array*)&this->__ptr, 1, SOAP_TYPE_ContainerFileArray))
        for (int i = 0; i < this->__size; i++)
        {    soap_embedded(soap, this->__ptr + i, SOAP_TYPE_IDCXDService__ContainerFile);
            this->__ptr[i].soap_serialize(soap);
        }
}

The indicator is on the highlighted line, but I suspect it failed in the soap_embedded call. I should also note that it fails on the first element in the malloc'd block (ie: when i == 0).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

给妤﹃绝世温柔 2025-01-11 13:41:14

在 C++ 中,您应该始终使用“new”而不是“malloc”,如下所示:

gSoapArray.__ptr = soap_new_ ns__ContainerFile(soap, gSoapArray.__size);

或者更好的是,在 gSOAP 头文件中使用 STL std::vector,如下所示:

#import "stlvector.h"
class ns__Container
{
public:
    xsd__long           containerId     0:1 = 0;
    xsd__string         name            0:1 = "";
    xsd__string         description     0:1 = "";
    std::vector<ns__ContainerFile> files           0:1 = NULL;
};

基本上,malloc 在 C++ 中不安全,因为实例的 VMT未初始化,因此动态方法调用会导致崩溃。

You should always use 'new' instead of 'malloc' in C++, as in:

gSoapArray.__ptr = soap_new_ ns__ContainerFile(soap, gSoapArray.__size);

Or even better, use STL std::vector in the gSOAP header file as follows:

#import "stlvector.h"
class ns__Container
{
public:
    xsd__long           containerId     0:1 = 0;
    xsd__string         name            0:1 = "";
    xsd__string         description     0:1 = "";
    std::vector<ns__ContainerFile> files           0:1 = NULL;
};

Basically, malloc is not safe in C++ because the VMT of the instance is not initialized so a dynamic method invocation leads to a crash.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文