Access violation and strange behavior of Visual St

2019-06-07 15:56发布

问题:

I'm writing a test application on DirectX11, and I have 2 classes "Box" and "camera" . "Box" is a cube which is to be drawn on the screen, and this is "camera":

class camera 
{ 
public :
const camera operator=(const camera& fv) const
{
    return fv;
}
XMVECTOR eye;
XMVECTOR at;
XMVECTOR up;
XMVECTOR right;
XMVECTOR left;
XMVECTOR down;
float pitch; //x
float roll; //z
float yaw; //y

XMMATRIX View;
XMMATRIX Projection;
camera();
camera(XMVECTOR eye, XMVECTOR at, XMVECTOR up, float movingOffset, float radius);
void Move(XMVECTOR Offset);
void MoveCameraRight(float offset);
void Rotate(XMVECTOR offset);
void MoveCameraLeft(float offset);

void MoveCameraUp(float offset);
void MoveCameraDown(float offset);
void MoveCameraCloser(float offset);
} ;

I'm working in Visual Studio 2012, and all was perfect, until I decided to build my solution under Release config. Camera constructor has always fallen on "Unhandled exception: Acces violation reading location..." on different addresses near 0x0. I know why it's happening, I've checked all of the pointers I've used, and I completely don't understand, what is happening. Here is the beginning of the file with the WinMain function:

#include <stdio.h>
#include "DIMouse.h"
#include <string>
#include <sstream>
#include <iostream>


HINSTANCE               g_hInst = nullptr;
HWND                    g_hWnd = nullptr;
HRESULT                 hr = S_OK;
D3D_DRIVER_TYPE         g_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVEL       g_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device*           g_pd3dDevice = nullptr;
ID3D11DeviceContext*    g_pImmediateContext = nullptr;
IDXGISwapChain*         g_pSwapChain = nullptr;
ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
ID3D11VertexShader*     g_pVertexShader = nullptr;
ID3D11PixelShader*      g_pPixelShader = nullptr;
ID3D11InputLayout*      g_pVertexLayout = nullptr;
ID3D11Buffer*           g_pVertexBuffer = nullptr;
ID3D11Buffer*           g_pConstantBuffer = nullptr;
ID3D11Buffer*           g_pIndexBuffer = nullptr;
XMMATRIX                g_World;                     // World matrix
XMMATRIX                g_View;           // View matrix
XMMATRIX                g_Projection;           // Projection matrix

int BOXES_COUNT = 50;
int Radius = 20;
FILE* fpsLog = NULL;
Box** boxes;
camera* cam;
FPS fps;
int calculationId = 0;

 HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow );
 HRESULT InitDevice();
 HRESULT InitGeometry();
 void parseArgs(LPWSTR  lpl);
void CleanupDevice();
LRESULT CALLBACK    WndProc( HWND, UINT, WPARAM, LPARAM );
void Render();
HRESULT InitCamera();   
void InitCubes(int boxesCount);
cDIObject DIObject;
cMouse Mouse;

 int WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,   _In_     LPWSTR lpCmdLine, _In_ int nCmdShow )
 {
//parse args
parseArgs( lpCmdLine );
UNREFERENCED_PARAMETER( hPrevInstance );
UNREFERENCED_PARAMETER( lpCmdLine );

  ....
     if (FAILED ( InitCamera()))
{
    .....

InitCamera() - a function, where I call the constructor, when all crashes:

HRESULT InitCamera()
{
  RECT rc;
   GetClientRect( g_hWnd, &rc );
   UINT width = rc.right - rc.left;           
   UINT height = rc.bottom - rc.top;   
   g_World = XMMatrixIdentity();

   XMVECTOR Eye = XMVectorSet( 0.0f, 0.0f, -45, 0.0f );  
   XMVECTOR At = XMVectorSet( 0.0f, 0.0f, 0.0f, 0.0f );    
   XMVECTOR Up = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );    
   g_View = XMMatrixLookAtLH( Eye, At, Up );
   g_Projection = XMMatrixPerspectiveFovLH( XM_PIDIV4, width / (FLOAT)height, 0.01f,    100.0f );
cam = (camera*)malloc(sizeof(camera));
  camera * c = new camera( Eye, At, Up, 0.5, Radius );
cam = c;

cam is a global pointer to camera class, don't look at me that way, this worked under VS for some time.

If I need to parse command line arguments, which are taken from lpCmdLine, I need to alloc memory, and I've thought, that the reason were memory allocations in the beginning of ..Main. I used malloc() and arrays ( with new and then delete ), but even if I'd called free() and used the delete operator, "access violation" also happened. But , now attention! Sometimes it worked under Visual Studio, when I hadn't tried to alloc memory, and didn't worked , when I just launched an .exe file. Then I decided to check out what would happen without memory allocations, and it worked under VS and outside ( when I launched the .exe ). But when I removed all mem allocations from code to see what would happen, I also got "Access violation..." on the line

   camera * c = new camera( Eye, At, Up, 0.5, Radius );

I have working solution under the Debug mode, and I decided to disable optimisations under Release, it worked under VS than and didn't work when I launched the .exe. I've tried everything and I don't know how to deal with this case. I've checked out again, I have no bad pointers. I've read something about memory leaks, but even if I 'd tried to delete or free() memory after my usage, it crashed anyway. I'm desperate.

回答1:

Assuming that you already checked and debugged all possible pointer issues (I have a doubt), the most probable bug is unaligned DirectXMath. XMVECTOR and XMMATRIX objects must be 16-byte aligned.

Possible solutions are:

  • Use aligned allocations
  • Do not use dynamic allocation (place objects on stack)
  • Use XMFLOATa and XMFLOATaXb (where a and b are dimensions) as storage (class members, function parameters, etc.) and convert to XMMATRIX and XMVECTOR (placed on ctack) just before calculations
  • Disable SSE intrinsics (put #define _XM_NO_INTRINSICS_ before include file). It will disable alignment requirement
  • Do not use DirectXMath (there are plenty other math libraries)

Probably you will find this two answers useful: one, two

C++ notes (offtopic):
- Never mix new/free, malloc/delete. You can not.
- We tend to avoid all four of this in C++. Prefer to use smart pointers: std::shared_ptr, std::unique_ptr, and their companion functions: std::make_shared, std::make_unique()
- This is a memory leak (memory allocated for cam is lost forever after assignment and you cannot release it anymore):

cam = (camera*)malloc(sizeof(camera));
camera * c = new camera( Eye, At, Up, 0.5, Radius );
cam = c;

- Do instead:

std::shared_ptr<Camera> cam;
...
cam = std::make_shared<Camera>(Eye, At, Up, 0.5, Radius);
- Global variables considered evil in C++
- Raw pointers considered evil in C++
- Check The Definitive C++ Book Guide and List ("Best Practices" and "Intermediate" sections)

Hope it helps somehow. Happy coding!