Korrumpierte Zeiger innerhalb einer Struktur als Parameter einer Methode



  • Hallo alle zusammen,
    ich habe ein Problem mit Pointern woran ich verzweifel.
    Und zwar bekomme ich eine Exception wenn ich vkCreateGraphicsPipelines(...) aufrufe.
    Nach ein wenig Debugging wurde mir klar, dass das Problem in der Methode InVulkanPipeline::CreateGraphicsPipelineCreateInfo liegt.
    Nach dem ich mir einen Breakpoint an der Stelle pipelineInfo.pVertexInputState = &vertexInputInfo; gesetzt habe konnte ich mit dem Cursor über die Stelle const VkPipelineVertexInputStateCreateInfo& vertexInputInfo in der Methode :CreateGraphicsPipelineCreateInfo gehen und bekam so folgende Informationen:
    sType VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO (19)
    pNext 0x00
    flags 0
    vertexBindingDescriptionCount 1
    pVertexBindingDescription {binding=3435973836 stride=3435973836 inputRate=-858993460}
    vertexAttributeDescriptionCount 2
    pVertexAttributeDescription {binding=3435973836 stride=3435973836 inputRate=-858993460}
    Anhand der Informationen kann ich entnehmen, dass die beiden Pointer pVertexBindingDescription und pVertexAttributeDescription irgendwie ins nirgendwo zeigen.

    Ich habe keine Ahnung wieso das nicht funktioniert, wenn ich zum Beispiel einfach den Code aus der Methode InVulkanPipeline::CreatePipelineVertexInputStateCreateInfo
    direkt an die Stelle kopiere wo der Methodenaufruf erfolgt funktioniert es.
    Ich hoffe ihr könnt mir helfen, ich glaube es ist irgendwas mit den Zeigern und Referenzen.
    Ich weiß einfach nicht mehr weiter und hoffe, dass ihr mir helfen könnt.
    Ich habe den Code angehängt.

    Gruß Pixma

    Header Datei
    /////////////////////
    class InVulkanPipeline
    {
    private:
    	...
    	VkGraphicsPipelineCreateInfo CreateGraphicsPipelineCreateInfo(
    		const VkPipelineShaderStageCreateInfo shaderStages[],
    		const VkPipelineVertexInputStateCreateInfo& vertexInputInfo,
    		const VkPipelineInputAssemblyStateCreateInfo& inputAssembly,
    		const VkPipelineViewportStateCreateInfo& viewportState,
    		const VkPipelineRasterizationStateCreateInfo& rasterizer,
    		const VkPipelineMultisampleStateCreateInfo& multisampling,
    		const VkPipelineColorBlendStateCreateInfo& colorBlending) const noexcept;
    
    	VkPipelineVertexInputStateCreateInfo CreatePipelineVertexInputStateCreateInfo(VertexSource vertexSource) const noexcept;
    
    public:
    	void CreateGraphicsPipeline(VkDevice logicalDevice, std::vector<ShaderPipeline> *shaderPipeline, VkPipelineLayout *pipelineLayout);
    
    };
    
    Cpp Datei
    /////////////////////
    void InVulkanPipeline::CreateGraphicsPipeline(VkDevice logicalDevice, std::vector<ShaderPipeline> *shaderPipeline, VkPipelineLayout *pipelineLayout)
    {
    
    	...
    	VkPipelineVertexInputStateCreateInfo vertexInputInfo = CreatePipelineVertexInputStateCreateInfo(shaderPipeline->at(i).vertexSource);
    
    	...
    
    	VkGraphicsPipelineCreateInfo pipelineInfo = CreateGraphicsPipelineCreateInfo(shaderStageInfo.data(),
    		vertexInputInfo, inputAssembly, viewportState, rasterizer, multisampling, colorBlending);
    	result = vkCreateGraphicsPipelines(logicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &(shaderPipeline->at(i).pipeline));
    	if (result != VK_SUCCESS) {
    		throw VulkanException(result, "Failed to create pipeline layout:");
    	}
    
    }
    
    VkPipelineVertexInputStateCreateInfo InVulkanPipeline::CreatePipelineVertexInputStateCreateInfo(VertexSource vertexSource) const noexcept
    {
    	auto bindingDescription = Vertex::getBindingDescription();
    	auto attributeDescriptions = Vertex::getAttributeDescriptions();
    
    	VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
    	vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
    
    	if (vertexSource == IN_VERTEX_SOURCE_STRUCT)
    	{
    		vertexInputInfo.vertexBindingDescriptionCount = 1;
    		vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size();
    		vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
    		vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
    	}
    	else if(vertexSource == IN_VERTEX_SOURCE_SHADER)
    	{
    		vertexInputInfo.vertexBindingDescriptionCount = 0;
    		vertexInputInfo.vertexAttributeDescriptionCount = 0;
    	}
    	else
    	{
    		// TODO IMPLEMENTEXCEPTION
    	}
    
    	return vertexInputInfo;
    }
    
    VkGraphicsPipelineCreateInfo InVulkanPipeline::CreateGraphicsPipelineCreateInfo(
    	const VkPipelineShaderStageCreateInfo shaderStages[],
    	const VkPipelineVertexInputStateCreateInfo& vertexInputInfo,
    	const VkPipelineInputAssemblyStateCreateInfo& inputAssembly,
    	const VkPipelineViewportStateCreateInfo& viewportState,
    	const VkPipelineRasterizationStateCreateInfo& rasterizer,
    	const VkPipelineMultisampleStateCreateInfo& multisampling,
    	const VkPipelineColorBlendStateCreateInfo& colorBlending) const noexcept
    {
    	VkGraphicsPipelineCreateInfo pipelineInfo = {};
    	pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
    	pipelineInfo.stageCount = 2;
    	pipelineInfo.pStages = shaderStages;
    	pipelineInfo.pVertexInputState = &vertexInputInfo;
    	pipelineInfo.pInputAssemblyState = &inputAssembly;
    	pipelineInfo.pViewportState = &viewportState;
    	pipelineInfo.pRasterizationState = &rasterizer;
    
    	pipelineInfo.pMultisampleState = &multisampling;
    	pipelineInfo.pColorBlendState = &colorBlending;
    	pipelineInfo.layout = m_pipelineLayout;
    	pipelineInfo.renderPass = m_renderPass;
    	pipelineInfo.subpass = 0;
    	pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
    	return pipelineInfo;
    }
    


  • Zeiger auf temporäre Objekte in einer Datenstruktur zu speichern, die möglicherweise den Scope des temporären Objekts überlebt ist generell einer schlechte Idee.

    Das ist einmal bei vertexInputInfo der Fall (Zeilen 29, 34, 83) und sehr warscheinlich auch bei bindingDescription / attributeDescriptions (Zeilen 44, 45, 54, 55),
    wobei man sich wegen dem auto nicht so ganz sicher sein kann.

    Letzteres ist ziemlich sicher auch die direkte Ursache für dein Problem:
    Bedenke, dass die Objekte bindingDescription und attributeDescriptions als automatische Objekte (hat nix mit dem auto zu tun!) hier nur innerhalb von
    CreatePipelineVertexInputStateCreateInfo() existieren, vertexInputInfo aber immer noch einen Zeiger auf diese hält, über den den Vulkan wahrscheinlich in
    vkCreateGraphicsPipelines() auf die Objekte zugreifen möchte. Dass diese Pointer zu dem Zeitpunkt auf Müll zeigen, ist daher nicht verwunderlich.

    Dasselbe Anti-Pattern wird dir wahrscheinlich auch mit vertexInputInfo zu einem späteren Zeitpunkt auf die Füße fallen.

    Tip: Da diese Beschreibungs-Strukturen konzeptionell zu dem gehören, was die Pipeline ausmacht, macht es Sinn, diese auch als Member von InVulkanPipeline
    zu speichern. Das hätte den Vorteil, dass die Zeiger darauf so lange gültig bleiben, wie das Pipeline-Objekt existiert.



  • Hallo Finnegan,

    danke für deinen Hinweis. Das wusste ich noch garnicht, aber das macht Sinn.
    Also wenn ich das richtig verstehe wird der Kontext gelöscht am Ende der Methode und die beiden Zuweisungen
    auto bindingDescription = Vertex::getBindingDescription();
    auto attributeDescriptions = Vertex::getAttributeDescriptions(); sind dann unbekannt, oder?
    Dies ist auch der Grund weshalb der Zeiger irgendwo ins Nirwana zeigt. Einfach weil die Variablen zerstört wurden.

    Ich habe jetzt einfach als Lösungsweg die beiden auto Variablen in die Klassendeklaration als Member Variablen hinzugefügt.
    Aktuell läuft es, aber ich werde den Code dann die Tage noch mal refactoren, damit mir in der Zukunft nicht die vertexInputInfo um die Ohren fliegt.
    Jedoch muss ich da dann noch mehr auslagern, weil ich für mehrere Strukturen aktuell diesen Weg gewählt hab.

    Vielen Dank,
    das hat mir sehr geholfen 🙂

    Gruß Pixma



  • Pixma schrieb:

    Das wusste ich noch garnicht, aber das macht Sinn.
    Also wenn ich das richtig verstehe wird der Kontext gelöscht am Ende der Methode und die beiden Zuweisungen
    auto bindingDescription = Vertex::getBindingDescription();
    auto attributeDescriptions = Vertex::getAttributeDescriptions(); sind dann unbekannt, oder?

    So ist es.
    Das ist allerdings elementares C++-Grundwissen, wenn du das also tatsächlich "nicht wusstest" und nicht nur "nicht erkannt" hast
    (ist nicht immer leicht auf den ersten Blick zu erkennen), kannst du dir eine Menge ziemlich garantierten Ärger ersparen, wenn du
    deine C++-Grundlagen nochmal etwas auffrischst, bevor du dich an ein komplexeres Programm wie dieses wagst - das ist immerhin
    nur einer der harmloseren Fallstricke, die C++ zu bieten hat (bitte als gut gemeinten Rat auffassen ;)).


Anmelden zum Antworten