非法访问内存,跟踪了一上午没有结果. 好心的请过来看看.(44分)

  • 主题发起人 Sterntaler
  • 开始时间
S

Sterntaler

Unregistered / Unconfirmed
GUEST, unregistred user!
程序还没有整理,觉得全贴出来不好。
跟踪到这个过程的 GetMem 行时访问非法内存.各位帮我看看,是不是这里出问题了?
我不知道错误是不是在这段代码,如果愿意看代码的话,请留下油箱。或者给我发
邮件(smnyx@21cn.com)

procedure TfmSrvMain.ServerSend(ASocket: TCustomWinSocket;
Cmd: Byte
Content: PChar
ContentLength: Integer);
var
NewContent: PChar;
SendLength: Integer;
begin
SendLength := ContentLength + SizeOf(Cmd);
GetMem(NewContent, SendLength)

try
NewContent[0] := Chr(Cmd);
System.Move(Content^, NewContent[1], ContentLength)

ASocket.SendBuf(NewContent^, SendLength);
finally
FreeMem(NewContent, SendLength);
end;
end;
 
T

twos

Unregistered / Unconfirmed
GUEST, unregistred user!
System.Move(Content^, NewContent[1], ContentLength)
改为
StrPCopy(......)
具体看帮助,处理pchar,一般是用这样的函数,还有其他的,帮助里面很详细
 
S

Sterntaler

Unregistered / Unconfirmed
GUEST, unregistred user!
谢谢 twos。
Move 也可以用来复制字符串啊,我想问题可能是在其他地方了(其实在我添加
//************** 之间的那些信息之前,发送8k的文件正常的),现在把出问题
可能相关的块列出来,这样你或许能看得更清楚一点:

procedure TfmSrvMain.ServerFileDownAnswer(ASocket: TCustomWinSocket;
Buffer: string);
{ File download request content: 'filename' + position }
{ Answer content: 'filename:' + size + FileEndFlag + FileContent }
{ FileEndFlag: 55: False, AA: True }
var
SendLen, DownLoadPos, fsize, offset: Integer;
Buf: PChar;
Del, FileEndFlag: Char;
begin
FServerState := ssFive;
{...}
CopyMemory(@DownLoadPos, PChar(Buffer), SizeOf(DownLoadPos));
Delete(Buffer, 1, 4);

with TFileStream.Create(Buffer, fmOpenRead) do
try
//*************
fsize := Size;
Del := ':';
FileEndFlag := Chr($55);
offset := 0;
SendLen := Length(Buffer) + SizeOf(fsize) + SizeOf(FileEndFlag) + fsize;

GetMem(Buf, SendLen);
CopyMemory(Buf, @Buffer[1], Length(Buffer))
// filename
Inc(offset, Length(Buffer));
CopyMemory(@Buf[offset], @Del, SizeOf(Char))
// Delimeter ':'
Inc(offset);
CopyMemory(@Buf[offset], @fsize, SizeOf(Integer))
// file size
Inc(offset, SizeOf(Integer));
//**************
try
Position := DownLoadPos;
if Read(Buf[offset + 1], fsize) <= fsize then // When size too big to send...
FileEndFlag := Chr($AA);

CopyMemory(@Buf[offset], @FileEndFlag, SizeOf(Char))
// file end flag(55 or AA)
ServerSend(ASocket, S_FILEDOWN_ACK, Buf, SendLen);
finally
FreeMem(Buf);
end;
finally
Free;
end;
end;
procedure TfmSrvMain.ServerRead(ASocket: TCustomWinSocket);
var
Buf: string;
Cmd: Byte;
begin
Buf := ASocket.ReceiveText;
CopyMemory(@Cmd, PChar(Buf), SizeOf(Cmd));
Delete(Buf, 1, 1);

case Cmd of
C_LOGIN_REQ: ServerCheckLogin(ASocket, Buf);
C_FILELIST_REQ: ServerFileListAnswer(ASocket);
C_MESSAGE_REQ: ServerMessageAnswer(ASocket);
C_LOGOFF_REQ: ServerLogoffAnswer(ASocket);
C_FILEDOWN_REQ: ServerFileDownAnswer(ASocket, Buf);
C_FILEUP_REQ: ServerFileUpAnswer(ASocket);
end;
end;

procedure TfmSrvMain.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
ServerRead(Socket);
end;
 
S

Sterntaler

Unregistered / Unconfirmed
GUEST, unregistred user!
我把 GetMem 和 FreeMem 换为 SysGetMem 和 SysFreeMem 后, 这下好了,
在 ServerRead 结束之后, 导致无效页错误被系统关闭. 由于基础不扎实,
看不懂汇编, 只知道在一个 ret $0100 的语句执行了就完蛋了...
那位好心人拉我一把吧!
 
B

bluely

Unregistered / Unconfirmed
GUEST, unregistred user!
帮你修改了一下,可以了:
procedure TfmSrvMain.ServerSend(ASocket: TCustomWinSocket;
Cmd: Byte
Content: PChar
ContentLength: Integer);
var
NewContent:array of byte;
SendLength: Integer;
begin
SendLength := ContentLength + SizeOf(Cmd);
setlength(newcontent,SendLength);
try
char(NewContent[0]) := Chr(Cmd);
CopyMemory(@NewContent[1],Content,ContentLength);
ASocket.SendBuf(NewContent,SendLength);
finally
Setlength(NewContent,0);
end;
end;
 
B

beta

Unregistered / Unconfirmed
GUEST, unregistred user!
或者用 AllocMem 分配内存试一试。

 
H

hlsl

Unregistered / Unconfirmed
GUEST, unregistred user!
你的那个SendBuf(NewContent^...)里面的NewContent^有问题吧?
好象应该是NewContent才对,是么?

 
C

chuguozhen

Unregistered / Unconfirmed
GUEST, unregistred user!
我是来学习的,我有一个问题不明白,希望各位能够解答,
System.Move(Content^, NewContent[1], ContentLength)
这一句的NewContent[1]能装下这一句的Content^吗?
Move的原型是:Move(const Source;var Dest;count:integer),我认为NewContent[1]一个字符的位置不能装下Content众的内容,除非Content^也是一个字符,如此的话count应该等于1,不知道我说的对不对,请大家帮我弄明白,谢谢!
 
S

Sterntaler

Unregistered / Unconfirmed
GUEST, unregistred user!
bluely: 像你那样使用字节数组还是不中, ASocket.SendBuf(NewContent[0],SendLength);

beta: 我用过了,问题还是没有解决. 很可能问题不是出在内存分配了.

hlsl, chuguozhen: var 参数传递地址. 实践一下.

非常感谢各位关心, 愿意帮我看一下代码么? 谢谢..
 
S

stargazer

Unregistered / Unconfirmed
GUEST, unregistred user!
回复chuguozhen,
NewContent[1]代表的是缓冲区字符串的首字符地址
 
L

leizengzheng

Unregistered / Unconfirmed
GUEST, unregistred user!
呵呵,Move(Content^, NewContent[1], ContentLength);中的NewContent 是压入堆栈的,
你的堆栈最大值小于ContentLength 导致非法访问内存,
 
S

Sterntaler

Unregistered / Unconfirmed
GUEST, unregistred user!
谢谢各位的关心。
接受 leizengzheng 的答案。
 
S

Sterntaler

Unregistered / Unconfirmed
GUEST, unregistred user!
结不了贴了?为什么?
 
Z

zhjwjan

Unregistered / Unconfirmed
GUEST, unregistred user!
serversend过程没问题。
 
S

Sterntaler

Unregistered / Unconfirmed
GUEST, unregistred user!
虽然我目前接受leizengzheng 的答案,但我还没有验证是否正确。leizengzheng 可告诉我在那里可以找到相关的资料吗?
内存拷贝操作是不必要的。
 
顶部