Recent

Author Topic: [Solved] Function returning AnsiString causes exception  (Read 7127 times)

FiftyTifty

  • Jr. Member
  • **
  • Posts: 59
[Solved] Function returning AnsiString causes exception
« on: February 05, 2017, 10:09:25 pm »
Yup, it's me again. And this one's not too obvious for my eyes.

The current code checks the first byte of the file for a specific file. This value has two variations, which dictates the location of the NPC data pointer. Navigate to the pointer, chuck the next 2000 bytes into an AnsiString, then output it back to the main program function MainProcedure().

For some reason, using the buffer as a result throws the following exception:

Quote
raised eception class
'External: SIGSEGV'.

At address 10000939D

Here's the code, with the problem line indicated.

Repo here.


Code: [Select]
function GetWholeNPCData(msMAPFile: TMemoryStream; strPointer: string): AnsiString;
var
  bufferNPCData: AnsiString;
begin

  {$IFDEF DEBUG} ShowMessage('Putting entire block of NPC data into buffer!'); {$ENDIF}

  msMAPFile.Seek(Hex2Dec(strPointer), 0);
  {$IFDEF DEBUG} ShowMessage('Used pointer to get to NPC data!'); {$ENDIF}
  msMAPFile.ReadBuffer(bufferNPCData, Hex2Dec('5DC'));
  {$IFDEF DEBUG} ShowMessage('Put NPC data into buffer!'); {$ENDIF}

  Result := bufferNPCData; <-- Problem code
  {$IFDEF DEBUG} ShowMessage('Sent the buffer!'); {$ENDIF}

end;

Considering this error is similar to the previous one I had, where I called .Create; directly on a TStringList variable, I thought it might be to do with something, like, using string instead of AnsiString somewhere along the line, but nada.
« Last Edit: February 06, 2017, 03:16:08 am by MajinCry »

wp

  • Hero Member
  • *****
  • Posts: 13554
Re: Function returning AnsiString causes exception
« Reply #1 on: February 05, 2017, 10:28:22 pm »
Please learn basic Pascal syntax of hex numbers. If you need in your program an integer with the hex value 5DC simply type $5DC, not Hex2Dec('5DC'). I know this is not your problem, but I must say that...

Your problem is that you read $5DC (=1500) bytes from the memorystream into a string buffer called bufferNPCdata, but you did not allocate memory for it. Simply call SetLength(bufferNPCdata, $5DC) before reading the buffer from the memory stream.

FiftyTifty

  • Jr. Member
  • **
  • Posts: 59
Re: Function returning AnsiString causes exception
« Reply #2 on: February 05, 2017, 10:43:08 pm »
Please learn basic Pascal syntax of hex numbers. If you need in your program an integer with the hex value 5DC simply type $5DC, not Hex2Dec('5DC'). I know this is not your problem, but I must say that...

Now that I think about it, I did use $ hex numbers ages ago, in one of my FO4Edit scripts. Huh. What's the variable used for hex values? I thought string was the best one for that, now I'm not too sure.

Quote
Your problem is that you read $5DC (=1500) bytes from the memorystream into a string buffer called bufferNPCdata, but you did not allocate memory for it. Simply call SetLength(bufferNPCdata, $5DC) before reading the buffer from the memory stream.

Oh, we have to size up AnsiStrings? Dear god, is there a way to truncate the beginning chars?

rvk

  • Hero Member
  • *****
  • Posts: 7043
Re: Function returning AnsiString causes exception
« Reply #3 on: February 05, 2017, 10:51:34 pm »
What's the variable used for hex values? I thought string was the best one for that, now I'm not too sure.
A hex value is just the same as a decimal or binary value. You use Integer, Byte, Word or any of those. Hex is just a representation of a number (integer etc.) Decimal or binary is another.
So all these lines are the same:
Code: Pascal  [Select][+][-]
  1. var
  2.   I: Integer;
  3. begin
  4.   I := %1010; // <- 10 in binary
  5.   I := $0A;  // <- 10 in hexadecimaal
  6.   I := 10;

Quote
Oh, we have to size up AnsiStrings? Dear god, is there a way to truncate the beginning chars?
You tried to use a readbuffer function which actually doesn't know if it's dealing with a string or array or anything else. Only in that case you need to extend the space for a string. A string is normally empty (nil) and if you use a string-function, extending the space is done automatically for you (i.e. Str := 'abc'; ). But if you are going to use ReadBuffer(String, 10); and String hasn't the space yet, the ReadBuffer isn't going to extend it. You need to do it yourself with SetLength(String, 10);

You can cut the beginning of the string with the normal Copy(String, 10, 200) commands etc.
(Note: Copy(String, 10); will return the string from position 10 to the end of the string.)

wp

  • Hero Member
  • *****
  • Posts: 13554
Re: Function returning AnsiString causes exception
« Reply #4 on: February 05, 2017, 11:00:05 pm »
Technically decimal and hex numbers are the same, they are just different ways to display the same sequence of "zero" and "one" bits.

Ansistrings are special pointers which are treated by the compiler such that the pointer details are hidden from you. Normally when you set a string variable to - say - 'Hello world' then the compiler automatically allocates enough memory for the characters because it knows how long the string is. But the method ReadBuffer of the memory stream is very general, the buffer can be anything, at compile time it is not clear which kind of data will be read. Therefore the compiler does not allocate the memory for the buffer although it knows how many bytes will be read from the stream. Allocating the buffer before read access is the task of the programmer who knows which data type will be read.

P.S.
rvk was faster... Nevertheless, I'll post my answer because sometimes reading the same explanation in different words makes things clearer (although the words are very similar here...)
« Last Edit: February 05, 2017, 11:01:52 pm by wp »

FiftyTifty

  • Jr. Member
  • **
  • Posts: 59
Re: [Solved] Function returning AnsiString causes exception
« Reply #5 on: February 05, 2017, 11:00:46 pm »
A hex value is just the same as a decimal or binary value. You use Integer, Byte, Word or any of those. Hex is just a representation of a number (integer etc.) Decimal or binary is another.
So all these lines are the same:

You tried to use a readbuffer function which actually doesn't know if it's dealing with a string or array or anything else. Only in that case you need to extend the space for a string. A string is normally empty (nil) and if you use a string-function, extending the space is done automatically for you (i.e. Str := 'abc'; ). But if you are going to use ReadBuffer(String, 10); and String hasn't the space yet, the ReadBuffer isn't going to extend it. You need to do it yourself with SetLength(String, 10);

You can cut the beginning of the string with the normal Copy(String, 10, 200) commands etc.
(Note: Copy(String, 10); will return the string from position 10 to the end of the string.)


Ooooh! We just assign $ to the values of the integer. I was trying to put $ at the beginning of the variable name. Heh.

So string functions also work on AnsiStrings, like how integer functions work on Byte, Word, etc.?

FiftyTifty

  • Jr. Member
  • **
  • Posts: 59
Re: Function returning AnsiString causes exception
« Reply #6 on: February 05, 2017, 11:03:49 pm »
Technically decimal and hex numbers are the same, they are just different ways to display the same sequence of "zero" and "one" bits.

Ansistrings are special pointers which are treated by the compiler such that the pointer details are hidden from you. Normally when you set a string variable to - say - 'Hello world' then the compiler automatically allocates enough memory for the characters because it knows how long the string is. But the method ReadBuffer of the memory string is very general, the buffer can be anything, at compile time it is not clear which kind of data will be read. Therefore the compiler does not allocate the memory for the buffer although it knows how many bytes will be read from the stream. Allocating the buffer before read access is the task of the programmer who knows which data type will be read.

P.S.
rvk was faster... Nevertheless, I'll post my answer because sometimes reading the same explanation in different words makes things clearer (although the words are very similar here...)

Decimal is the value, hex is the raw memory value. I've done enough in CheatEngine to know that much, at least.  Cheat Engine taught me well.

And yeah man, props to you both for the replies. Much better than the "You should give up programming" comments I've been given, when discussing fairly basic stuff like this on other forums. Es bueno.

rvk

  • Hero Member
  • *****
  • Posts: 7043
Re: [Solved] Function returning AnsiString causes exception
« Reply #7 on: February 05, 2017, 11:44:07 pm »
So string functions also work on AnsiStrings, like how integer functions work on Byte, Word, etc.?
Yep. There are some function that work especially on string (utf8) or ansistring. But most functions will work on both and often the compiler will add conversion of string types when the other type is needed.

Decimal is the value, hex is the raw memory value. I've done enough in CheatEngine to know that much, at least.  Cheat Engine taught me well.
Actually, no :) bits (1s and 0s) are the raw memory value at memory-chip level. Hex is just a way lots of memory-viewers show you the value. This is because hex is closer to binary than decimal. You can see that in $FF is 255. And $F is %1111 which is 16. So most hex-editors show, well... Hex values :D But remember... It's just one of the possible representations. If I want to view memory as binary it would look like a series of 1s and 0s or I could also show it as decimal values with spaces between them or even as ascii characters. But you can't say that raw memory is hexidecimal... It's just often presented like that.

lainz

  • Hero Member
  • *****
  • Posts: 4743
  • Web, Desktop & Android developer
    • https://lainz.github.io/
Re: [Solved] Function returning AnsiString causes exception
« Reply #8 on: February 05, 2017, 11:56:14 pm »
Hi, what great initiative of game hacking, is really good.

I see you're using GitHub, some files aren't needed to be uploaded in the repository like .exe, the lib folder and all it's contents and many others that aren't source code.

For example, you can put a .gitignore file in your repository, something like this (https://github.com/bgrabitmap/bgracontrols/blob/master/.gitignore)

And then these files will not be listed as files to be uploaded to the repository. For those files you have in there you can safely remove them. And then your source will be clean of unnecessary files.

I see you're using a kind of .gitignore is not bad but doesn't include executables and fpc related files.

FiftyTifty

  • Jr. Member
  • **
  • Posts: 59
Re: [Solved] Function returning AnsiString causes exception
« Reply #9 on: February 06, 2017, 12:43:52 am »
Hi, what great initiative of game hacking, is really good.

I see you're using GitHub, some files aren't needed to be uploaded in the repository like .exe, the lib folder and all it's contents and many others that aren't source code.

For example, you can put a .gitignore file in your repository, something like this (https://github.com/bgrabitmap/bgracontrols/blob/master/.gitignore)

And then these files will not be listed as files to be uploaded to the repository. For those files you have in there you can safely remove them. And then your source will be clean of unnecessary files.

I see you're using a kind of .gitignore is not bad but doesn't include executables and fpc related files.

I've just been copy-pasting the whole Lazarus project folder into Github's project folder, and use the program to manage it all. Guess it can't hurt to keep the size down. Tah for the heads up.

FiftyTifty

  • Jr. Member
  • **
  • Posts: 59
Re: [Solved] Function returning AnsiString causes exception
« Reply #10 on: February 06, 2017, 01:09:31 am »
Got around to adding the SetLength() commands to GetWholeNPCData() & GetNPCData in MainCode.pas, as well as to MainProcedure(). Still throws an exception when returning the AnsiString.

I thought maybe calling SetLength(Result, 1500); would fix it, since I'm outputting an AnsiString, but nah. Throws the same exception.

Cyrax

  • Hero Member
  • *****
  • Posts: 836
Re: Function returning AnsiString causes exception
« Reply #11 on: February 06, 2017, 02:00:01 am »
You need to change
Code: Pascal  [Select][+][-]
  1. msMAPFile.ReadBuffer(bufferNPCData, $5DC);
to
Code: Pascal  [Select][+][-]
  1. msMAPFile.ReadBuffer(bufferNPCData[1], $5DC);

Indexing of Pascal String starts on one, not from zero index.

Cyrax

  • Hero Member
  • *****
  • Posts: 836
Re: Function returning AnsiString causes exception
« Reply #12 on: February 06, 2017, 02:02:30 am »
Also change all instances of Hex2Dec to real hexadecimal notations.

FiftyTifty

  • Jr. Member
  • **
  • Posts: 59
Re: Function returning AnsiString causes exception
« Reply #13 on: February 06, 2017, 03:15:58 am »
You need to change
Code: Pascal  [Select][+][-]
  1. msMAPFile.ReadBuffer(bufferNPCData, $5DC);
to
Code: Pascal  [Select][+][-]
  1. msMAPFile.ReadBuffer(bufferNPCData[1], $5DC);

Indexing of Pascal String starts on one, not from zero index.

Un-intuitive quirks. They're always fun.

Also change all instances of Hex2Dec to real hexadecimal notations.

Is there a particular reason for that? I've gone ahead and changed 'em all except for where I use strPointer. I'm guessing there's a slight memory benefit, but mostly as a guidance for good programming.

 

TinyPortal © 2005-2018