关于访问冲突和堆溢出的离奇错误

0

以下是完整代码,运行时会在238行出现访问冲突和堆栈溢出的错误,但238行是一个累加赋值语句。查看已申请的堆内存,大约0.5GB。应该不至于溢出啊?

编译环境:vs2017

测试输入:[任意一运行的程序的窗口的标题] 1017

正常退出时会显示pause命令的输出(按任意按键继续)不正常退出会闪退

改为使用安全函数后,223行出现新错误,图片在1群里

liveRPG.h

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <malloc.h>
#include <process.h>
#include <Windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, "ws2_32.lib")

//#include "cJSON.h"

#define PAUSE do{system("pause");}while(0)

typedef struct GameStruct
{
	HWND	hwnd;
	HDC		hdc;
} Game;

main.c

// #define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include "liveRPG.h"

char gameWndTitle[100];
char liveRoomNum[10];

Game *rpg;
Game *choiseWnd;

HINSTANCE hInstance;

_Bool GetGameWndInfor(Game *G, char* WndName);
LRESULT CALLBACK ChoiseWndProc(HWND, UINT, WPARAM, LPARAM);
void CreateChoiseWnd(void* null);
_Bool GetBiliLiveRoomCommit(char* lrn, char* r);

int main(void)
{
	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
	DWORD mode;
	GetConsoleMode(hStdin, &mode);
	mode &= ~ENABLE_QUICK_EDIT_MODE;  //移除快速编辑模式
	mode &= ~ENABLE_INSERT_MODE;      //移除插入模式
	SetConsoleMode(hStdin, mode);
	char strTitle[255];
	GetConsoleTitleA(strTitle, 255);
	HWND hw = FindWindowA("ConsoleWindowClass", strTitle);
	CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(hStdout, &CursorInfo);
	CursorInfo.bVisible = FALSE;
	SetConsoleCursorInfo(hStdout, &CursorInfo);
	CONSOLE_FONT_INFO consoleCurrentFont;
	GetCurrentConsoleFont(hStdout, FALSE, &consoleCurrentFont);
	int iconY = consoleCurrentFont.dwFontSize.Y;

	hInstance = GetModuleHandle(NULL);
	SetConsoleTitleA("liveRPG!");
	rpg = (Game*)malloc(sizeof(Game));		//游戏本身
	choiseWnd = (Game*)malloc(sizeof(Game));	//为了显示附加信息而创建的全透明窗口

    printf("\n"
		".__  .__            ____________________  ________ \n"
		"|  | |__|__  __ ____\\______   \\______   \\/  _____/ \n"
		"|  | |  \\  \\/ // __ \\|       _/|     ___/   \\  ___ \n"
		"|  |_|  |\\   /\\  ___/|    |   \\|    |   \\    \\_\\  \\\n"
		"|____/__| \\_/  \\___  >____|_  /|____|    \\______  /\n"
		"                   \\/       \\/                  \\/ \n"
		"---------------------------------------------------\n"
		"Welcome! There is liveRPG, you can use me to live RPG game and viewer can choise the game's option.\n"
		"please type the game's Window title\n"
		">");
	scanf_s("%[^\n]", &gameWndTitle, 100);
	//HDC i1 = GetDC(LoadImage(hInstance, MAKEINTRESOURCE( IDI_ICON1 ), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR));
	//HDC i2 = GetDC(LoadImage(hInstance, MAKEINTRESOURCE( IDI_ICON2 ), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR));
	//BitBlt(GetDC(GetConsoleWindow()), 0, iconY * 12, iconY * 2, iconY * 2, i1, 0, 0, SRCCOPY);

	printf("\n\nplease type your live room number\n>");
	scanf_s("%s", &liveRoomNum, 10);

	if (!GetGameWndInfor(rpg, gameWndTitle))
	{
		free(rpg);
		free(choiseWnd);
		return (-1);
	}

	_beginthread(CreateChoiseWnd, 0, NULL);

	Sleep(100);

	char* res = NULL;

	//while (TRUE)
	{
		//BitBlt(choiseWnd->hdc, 0, 0, 1024, 768, rpg->hdc, 0, 0, SRCCOPY);
		GetBiliLiveRoomCommit(liveRoomNum, res);

		printf("%s", res);

		free(res);
		Sleep(10);
	}

	PAUSE;
	free(rpg);
	free(choiseWnd);
	return 0;
}

_Bool GetGameWndInfor(Game *G, char* WndName)
{
	//WCHAR wWndName[100];
	//mbtowc(wWndName, WndName, strlen(WndName));

	G->hwnd = FindWindowA(NULL, WndName);
	if (!G->hwnd)
	{
		return FALSE;
	}

	G->hdc = GetDC(G->hwnd);
	if (!G->hdc)
	{
		return FALSE;
	}

	return TRUE;
}

void CreateChoiseWnd(void* null)
{
	WNDCLASS wc = { 0 };
	wc.hbrBackground = CreateSolidBrush(RGB(0, 255, 0));
	wc.lpfnWndProc = ChoiseWndProc;
	wc.lpszClassName = L"liveRPG choise wnd";
	wc.hInstance = GetModuleHandle(NULL);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hIcon = LoadIcon(0, IDI_APPLICATION);
	RegisterClass(&wc);

	choiseWnd->hwnd = CreateWindowExW(0l/*WS_EX_LAYERED*/,
		L"liveRPG choise wnd", L"",
		WS_POPUP | WS_VISIBLE,
		CW_USEDEFAULT, 0,
		1024, 768,
		NULL, NULL, GetModuleHandle(NULL), NULL);
	//SetLayeredWindowAttributes(W->hwnd, RGB(0, 0, 0), 1, LWA_COLORKEY | LWA_ALPHA);
	ShowWindow(choiseWnd->hwnd, SW_SHOW);
	UpdateWindow(choiseWnd->hwnd);

	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return;
}

LRESULT CALLBACK ChoiseWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		choiseWnd->hdc = BeginPaint(hWnd, &ps);
		// TODO: 在此处添加使用 hdc 的任何绘图代码...
		EndPaint(hWnd, &ps);
	}
	break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

_Bool GetBiliLiveRoomCommit(char* lrn, char* r)
{
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	if (WSAStartup(sockVersion, &wsaData) != 0)
	{
		fprintf(stderr, "error - WSAStartup!");
		return FALSE;
	}

	SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (slisten == INVALID_SOCKET)
	{
		fprintf(stderr, "error - invalid socket!");
		return FALSE;
	}

	/*
	ADDRINFO addr;
	ADDRINFO hint;
	hint.ai_family = AF_INET;                   /*  hint 的限定设置  
	hint.ai_socktype = SOCK_STREAM;     /*   这里可是设置 socket type    比如  SOCK——DGRAM 
	hint.ai_flags = AI_ALL;                    /* flags 的标志很多  。常用的有AI_CANONNAME;  
	hint.ai_protocol = 0;                               /*  设置协议  一般为0,默认 
	hint.ai_addrlen = 0;                                /*  下面不可以设置,为0,或者为NULL  
	hint.ai_canonname = NULL;
	hint.ai_addr = NULL;
	hint.ai_next = NULL;
	if (!GetAddrInfoW(L"api.live.bilibili.com", L"http", &hint, &addr))
	{
		fprintf(stderr, "error - get host IP error!");
		return FALSE;
	}*/

	HOSTENT *remoteHost;
	if ((remoteHost = gethostbyname("api.live.bilibili.com")) == NULL)       //通过主机名获取地址
	{
		fprintf(stderr, "error - can not find IP!");
		return FALSE;
	}
	int a = WSAGetLastError();

	//char addrTMP[5];
	//strcpy(addrTMP, remoteHost->h_addr_list[0]);
	SOCKADDR_IN serAddr;
	serAddr.sin_family = AF_INET;
	serAddr.sin_port = htons(80);
	serAddr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr*)remoteHost->h_addr_list[0]));

	if (connect(slisten, ((const SOCKADDR *)(&serAddr)), sizeof(serAddr)))
	{
		fprintf(stderr, "error - connect error!");
		return FALSE;
	}

	char *buffer = (char*)malloc(321 + strlen(lrn));
	strcpy_s(buffer, 45, "GET /xlive/web-room/v1/dM/gethistory?roomid=");
	strcat_s(buffer, strlen(lrn) + 1, lrn);
	strcat_s(buffer, 286, " HTTP/1.1\r\nHost: api.live.bilibili.com\r\nAccept: */*\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36\r\nConnection: keep-alive\r\nCache-Control: no-cache\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n\r\nroomid=");
	strcat_s(buffer, strlen(lrn) + 1, lrn);
	send(slisten, buffer, (int)strlen(buffer), 0);

	unsigned long long l = 1;
	int test = 0;
	char Tmp[1];
	//char *testC = (char*)malloc(1024);
	//memset(testC, 0, 1024);
	_Bool isHeader = TRUE;
	_Bool isN = FALSE;
	while (isHeader)
	{
		l = recv(slisten, Tmp, 1, 0);
		test = WSAGetLastError();
		switch (*Tmp)
		{
		case '\r':
			break;
		case '\n'://判断HTTP头是否接受完毕
			if (isN == TRUE)
				isHeader = FALSE;
			isN = TRUE;
			break;
		default:
			isN = FALSE;
			break;
		}

		//strcat(testC, Tmp);
	}
	//free(testC);

	char *jsonTmp = (char*)malloc(1025);
	unsigned long long sum = 0;
	while (l > 0)
	{
		l = recv(slisten, Tmp, 1024, 0);
		strcat_s(jsonTmp, l + 1, Tmp);
		sum = sum + l;
		jsonTmp = (char*)realloc(jsonTmp, sum + 1026);
		if (l < 1024)
			break;
	}
	free(jsonTmp);
	char *JSON = (char*)malloc(sum);
	strcpy_s(JSON, sum, jsonTmp);
	JSON[sum + 1] = '\0';

	r = JSON;

	closesocket(slisten);
	WSACleanup();
	free(buffer);

	return TRUE;
}
ava
Billraozihan

2021-2-22

0

你的代码不完整,无法调试。

你自己可以很容易的调试呀,直接单步,看执行在哪里出问题就好了

至于 socket 的问题,给你个例子学习吧:https://codebus.cn/teternity/a/minesweeper-online

ava
慢羊羊

2021-2-22

调试了一下,send函数成功,recv函数返回错误SOCKET_ERROR - Billraozihan 2021-2-22
@Billraozihan 继续调试,你就会看到为什么没有退出这个函数。 - 慢羊羊 2021-2-22
@慢羊羊 找到了,就是recv无法返回http头,导致无法跳出第一个while循环 - Billraozihan 2021-2-22