2014-01-24 3 views
0

이 오류가 발생하여 델파이 7에 있던 프로젝트를 디버깅하고 델파이 XE2로 업그레이드하고 여러 가지 방법으로 같은 오류가 발생합니다.

First chance exception at $006DC660. Exception class $C0000005 with message 'access violation at 0x006dc660 read of address 0xffffffff' 

이는 방법 중 하나입니다 : 내가 검색 좀 나는 비슷한 문제를 설명하는 사람을 발견, 그가 증분 링커되지 않습니다 때 작동 긍정

PFI = ^TFI;   
TFI = record 
Id   : TToken; 
Name  : TName; 
Parameters : string; 
end; 

function TListFI.IsIn(S: PChar): PFI; 

    function SearchName2(Item: PFI):Boolean; 
    var N1, N2: PChar; 
    begin 
    N1:= StrNew(Item^.Name); 
    N2:= StrNew(S); //Here is the issue 
    SearchName2:= (StrComp(StrUpper(N1), StrUpper(N2)) = 0); 
    StrDispose(N1); 
    StrDispose(N2); 
    end; 

begin 
    IsIn:= PFI(FirstThat(@SearchName2)); 
end; 

, 누군가가 말해 줄 수 이 상황을 해결하기 위해 무엇을 어디서 또는 제공 할 것인지 조언 해주십시오. 이제 @ 분리

[EDIT]

| SIN 나에게 다음과 같은 오류를 범 = PFI (FirstThat (SearchName2));

E2010 Incompatible types: 'TObject' and 'PFI' 

제가 도움이 될지 확인하기 위해 FirstThat 절차를 추가하고 있습니다. S 유형 PChar의입니다

TFuncionColeccion = function (Elemento: TObject): Boolean; 

function TColeccion.FirstThat (Rutina: TFuncionColeccion): TObject; 
var 
    i: Integer; 
begin 
    For i:=0 to Count-1 do 
    if Rutina(Items[i]) then 
    begin 
     FirstThat:=Items[i]; 
     exit; 
    end; 
    FirstThat:=nil; 
end; 
+3

무엇이'StrNew'를 사용하게 만들었습니까? 첫 번째 단계는 내 코드베이스에서 삭제하는 것입니다. –

+0

나는이 프로젝트를 받았고 몇몇 학생들의 손에 들어갔다. 무엇이 insted 사용할 수 있고 왜 그것을 expunge? 주소를 추가하겠습니다. – sandiego

+1

null로 끝나는 문자열의 힙 할당에는주의 깊은 메모리 관리가 필요합니다. 코드가 누수로부터 보호하기 위해 try/finally 루프를 빠뜨린다. 오늘의 델파이에서는'string'을 사용할 것입니다. 당신은'PAnsiChar'와'PWideChar'를 간단한 할당 인'string'으로 직접 변환 할 수 있습니다. –

답변

5

FirstThat 함수가 무엇인지 명확하게 나타내는 포인터로 로컬 (중첩 된) 프로 시저를 호출하는 것은 오류입니다. 컴파일러는 스택을 사용하여 로컬 함수를 호출하고 부모 범위의 변수 (코드에서 S)에 액세스 할 수 있도록 특수한 작업을 수행해야하지만 컴파일러는 로컬 함수가 직접 호출 될 때만 이러한 특수 작업을 수행 할 수 있습니다. 컴파일러는 FirstThat에 대한 인수가 로컬 함수이기 때문에 FirstThat이 가리키는 함수를 호출 할 때 특수 코드를 포함하지 않는다는 것을 알 수 없습니다.

결론은 함수 내부의 스택이 예상대로 설정되지 않아서 이상한 증상이 나타날 수 있다는 것을 의미합니다. 다른 방법을 사용해야합니다. 어쩌면 SearchName2을 두 개의 인수로하는 함수로 만든 다음 FirstThat을 작성하여 함수 인수로 전달할 수있는 매개 변수로 S을 수락하십시오.

함수 포인터를 만들 때 @ 연산자를 사용할 필요가 없습니다. 당신이 할 때, 컴파일러는 타입 검사를 건너 뛰는 경향이 있습니다. 이것은 당신이 처음에 FirstThat에 로컬 함수 포인터를 넘기는 것을 허용합니다. 전달할 함수가 필요한 프로토 타입과 실제로 일치하면 컴파일러는 @ 연산자없이 전달할 수 있습니다.

4

당신은

StrNew(S) 

에서 액세스 위반을보고하고있다. 확률이 1에 가깝다는 설명은 S이 실제로는 NULL 종료 배열 WideChar의 포인터가 아닙니다.

델파이 7에서 PCharPAnsiChar의 별명입니다. 이는 AnsiChar의 널 종료 배열에 대한 포인터, 즉 8 비트 문자입니다. 델파이 XE2에서, PCharPWideChar의 별칭이고, 널 종료 배열 WideChar의 포인터, 즉 16 비트 문자입니다.

무엇이 StrNew인지 이해하는 데 도움이됩니다. null 문자를 찾을 때까지 배열을 찾습니다. 단일 0 바이트 인 8 비트 텍스트의 경우. 16 비트 텍스트의 경우 null은 0 인 16 비트 단어입니다. 그런 다음 입력 문자열과 동일한 길이의 새 메모리 블록을 할당하고 해당 새 메모리에 복사본을 만듭니다. 소스 코드는 다음과 같습니다

function StrNew(const Str: PWideChar): PWideChar; 
var 
    Size: Cardinal; 
begin 
    if Str = nil then Result := nil else 
    begin 
    Size := StrLen(Str) + 1; 
    Result := StrMove(WideStrAlloc(Size), Str, Size); 
    end; 
end; 

만 그럴듯한 고장 모드가 StrLen 배열을 산책 할 때, 그것을 읽고 잘못된 메모리를 시도한다는 것입니다. 그리고 그것은 입력 매개 변수가 유효하지 않은 경우에만 발생할 수 있습니다. 즉, 이것은 사용자가 프로그래밍 오류가되어야합니다.

한 가지 가능한 설명은 사실 16 비트 텍스트를 전달하겠다고 약속했지만 실제로이 기능에 8 비트 텍스트를 전달한다는 것입니다. 특히 유니 코드 변경에 대해 아직 완전히 익숙하지 않은 경우 쉽게 실수 할 수 있습니다. 8 비트 텍스트는 터미네이터가 없지만 뒤따라 오는 바이트는 0이 아닙니다. 또는 0 바이트는 시작점에서 홀수 번 오프셋으로 떨어집니다. 그리고 나서 StrNew은 버퍼를 계속 걷지 만, 이제 끝나기 때문에 할당되지 않은 주소로 넘어 가기 전에 0 단어를 찾지 못합니다. 그리고 그것은 액세스 위반입니다.

즉 경우 그럼 해결책이 될 것입니다 중 하나

  • 변경 함수의 매개 변수 유형 PAnsiChar의, 그리고 호출 사이트에서 의심스러운 주조를 해결합니다.
  • 함수 16 비트 텍스트를 필요한대로 전달하십시오.

업데이트 할 때 읽을 수없는 주소 인 0xffffffff이 포함됩니다. 이것은 -1입니다. 그리고 그것은 오류의 가장 황당한 것으로 보입니다. 포인터가 완전히 가짜입니다! 정확한 오류 메시지는 StrNew(PChar(-1)) 코드로 재생할 수 있습니다.

여기 왜 포인터가 가짜인지 알려주는 정보가 충분하지 않습니다. 다행스럽게도 문제를 해결할 수있는 디버깅 및 진단 기법을 배웠 으면 좋겠다. 적어도 이제는 오류가 코드에 있음을 알게되었습니다.

BuscaName2와 SearchName2가 동일하고 동일한 것으로 가정하면 더 이상 보지 않아도됩니다. 로컬 프로 시저는 포함 된 함수에서만 호출 할 수 있습니다. @ Rob이 올바르게 말했듯이 @ 절차의 사용은 거의 항상 부정확하며 코드에 심각한 문제가 있음을 경고하는 표시입니다.

관련 문제