Page 1 of 1

Checking if memory is valid

Posted: Wed Apr 16, 2014 10:55 pm
by Dreamland Fantasy
Hi there,

I'm looking for a way to verify if a memory ID is valid. As an example, take the following code:

Code: Select all

*mem = AllocateMemory(1024)

Debug *mem
Debug MemorySize(*mem)      ; Valid memory ID here

FreeMemory(*mem)

Debug *mem
Debug MemorySize(*mem)      ; Not a valid memory ID anymore
Essentially what I am wanting to do is create a procedure that takes a memory ID as a parameter, but I want to verify that it is valid so that it can return with a fail code if necessary.

Kind regards,

Francis

Re: Checking if memory is valid

Posted: Wed Apr 16, 2014 11:14 pm
by Thunder93

Code: Select all

*MemoryID = AllocateMemory(1000) 

*Pointer = *MemoryID
CopyMemoryString("Hello ", @*Pointer)
CopyMemoryString("World")

*NewMemoryID = ReAllocateMemory(*MemoryID, 2000) ; need more memory 
If *NewMemoryID 
  ; work with *NewMemoryID now with size 2000 
  ;
  Debug "The old content is still here:" 
  Debug PeekS(*NewMemoryID) 
  FreeMemory(*NewMemoryID) 
Else 
  ; resizing failed, keep working with *MemoryID (size 1000) 
  ; 
  FreeMemory(*MemoryID) 
EndIf 
Example from help :)

Re: Checking if memory is valid

Posted: Wed Apr 16, 2014 11:32 pm
by Dreamland Fantasy
Unless I'm missing something (which is entirely possible), I don't see how that solves my problem. I've updated my example to give a better reflection of what I am trying to achieve:

Code: Select all

Procedure MyProc(*mem)
  Debug *mem
  If *mem                   ; I want to check if *mem is valid
    Debug MemorySize(*mem)  
  Else
    ProcedureReturn 0       ; *mem not valid, so fail
  EndIf
EndProcedure

*mem = AllocateMemory(1024)
MyProc(*mem)      ; Valid memory ID here
FreeMemory(*mem)
MyProc(*mem)      ; Not a valid memory ID anymore
Kind regards,

Francis

Re: Checking if memory is valid

Posted: Thu Apr 17, 2014 12:22 am
by Thunder93
You mean like the way the following does... ? :wink:

Code: Select all

Procedure MyProc(*mem)
  If *mem                   ; I want to check if *mem is valid
    Debug "*mem is valid"
  Else
    Debug "*mem isn't valid"
    ProcedureReturn 0       ; *mem not valid, so fail
  EndIf
EndProcedure

*mem = AllocateMemory(1024)
MyProc(*mem)      ; Valid memory ID here
FreeMemory(*mem) : *mem = 0
MyProc(*mem)      ; Not a valid memory ID anymore

Re: Checking if memory is valid

Posted: Thu Apr 17, 2014 12:36 am
by Dreamland Fantasy
But the procedure would still produce an error if garbage is put into the parameter. I want to check if what is passed is valid, something like an IsMemory(*mem) function.

Kind regards,

Francis

Re: Checking if memory is valid

Posted: Thu Apr 17, 2014 12:42 am
by Thunder93
What you are looking for, it has been requested in the past.

First read thoroughly

Re: Checking if memory is valid

Posted: Thu Apr 17, 2014 12:51 am
by Dreamland Fantasy
Many thanks for those links.

So, in a nutshell, having an IsMemory() function is bad programming practice. I'll need to have a think about redesigning that part of my code then.

Kind regards,

Francis

Re: Checking if memory is valid

Posted: Thu Apr 17, 2014 5:03 pm
by JHPJHP
Not sure if the following helps...
- Windows only

I used the [ divide by 0 ] exception to demonstrate how it works, but maybe there is an exception that fits your requirements:

Code: Select all

Procedure UnhandledExceptionFilter(*ep.EXCEPTION_POINTERS)
  ExceptionCode = *ep\ExceptionRecord\ExceptionCode
  ExceptionFlags = *ep\ExceptionRecord\ExceptionFlags

  Select ExceptionCode
    Case #EXCEPTION_ACCESS_VIOLATION
      ExceptionFlags = 1
      ErrorMessage.s = "EXCEPTION_ACCESS_VIOLATION"
    Case #EXCEPTION_ARRAY_BOUNDS_EXCEEDED
      ErrorMessage.s = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"
    Case #EXCEPTION_BREAKPOINT
      ErrorMessage.s = "EXCEPTION_BREAKPOINT"
    Case #EXCEPTION_DATATYPE_MISALIGNMENT
      ErrorMessage.s = "EXCEPTION_DATATYPE_MISALIGNMENT"
    Case #EXCEPTION_FLT_DENORMAL_OPERAND
      ErrorMessage.s = "EXCEPTION_FLT_DENORMAL_OPERAND"
    Case #EXCEPTION_FLT_DIVIDE_BY_ZERO
      ErrorMessage.s = "EXCEPTION_FLT_DIVIDE_BY_ZERO"
    Case #EXCEPTION_FLT_INEXACT_RESULT
      ErrorMessage.s = "EXCEPTION_FLT_INEXACT_RESULT"
    Case #EXCEPTION_FLT_INVALID_OPERATION
      ErrorMessage.s = "EXCEPTION_FLT_INVALID_OPERATION"
    Case #EXCEPTION_FLT_OVERFLOW
      ErrorMessage.s = "EXCEPTION_FLT_OVERFLOW"
    Case #EXCEPTION_FLT_STACK_CHECK
      ErrorMessage.s = "EXCEPTION_FLT_STACK_CHECK"
    Case #EXCEPTION_FLT_UNDERFLOW
      ErrorMessage.s = "EXCEPTION_FLT_UNDERFLOW"
    Case #EXCEPTION_ILLEGAL_INSTRUCTION
      ErrorMessage.s = "EXCEPTION_ILLEGAL_INSTRUCTION"
    Case #EXCEPTION_IN_PAGE_ERROR
      ErrorMessage.s = "EXCEPTION_IN_PAGE_ERROR"
    Case #EXCEPTION_INT_DIVIDE_BY_ZERO
      ErrorMessage.s = "EXCEPTION_INT_DIVIDE_BY_ZERO"
    Case #EXCEPTION_INT_OVERFLOW
      ErrorMessage.s = "EXCEPTION_INT_OVERFLOW"
    Case #EXCEPTION_INVALID_DISPOSITION
      ErrorMessage.s = "EXCEPTION_INVALID_DISPOSITION"
    Case #EXCEPTION_NONCONTINUABLE_EXCEPTION
      ErrorMessage.s = "EXCEPTION_NONCONTINUABLE_EXCEPTION"
    Case #EXCEPTION_PRIV_INSTRUCTION
      ErrorMessage.s = "EXCEPTION_PRIV_INSTRUCTION"
    Case #EXCEPTION_SINGLE_STEP
      ErrorMessage.s = "EXCEPTION_SINGLE_STEP"
    Case #EXCEPTION_STACK_OVERFLOW
      ErrorMessage.s = "EXCEPTION_STACK_OVERFLOW"
    Default
      ExceptionFlags = 1
      ErrorMessage.s = "EXCEPTION_UNKNOWN"
  EndSelect

  If ExceptionFlags
    ExceptionType.s = Chr(10) + Chr(10) + "EXCEPTION_NONCONTINUABLE"
  Else
    ExceptionType.s = Chr(10) + Chr(10) + "EXCEPTION_CONTINUABLE"
  EndIf
  MessageRequester("Error", ErrorMessage + ExceptionType)

  If ExceptionFlags
    SetUnhandledExceptionFilter_(#Null)
    Result = #EXCEPTION_EXECUTE_HANDLER

    If #PB_Compiler_Debugger : End : EndIf

  Else
    *ep\ContextRecord\Eip + 2
    Result = #EXCEPTION_CONTINUE_EXECUTION
  EndIf
  ProcedureReturn Result
EndProcedure

Macro TRY
  DisableDebugger
  SetUnhandledExceptionFilter_(@UnhandledExceptionFilter())
EndMacro

Macro ENDTRY
  SetUnhandledExceptionFilter_(#Null)
  EnableDebugger
EndMacro

Procedure MyProc(*mem)
  Debug *mem

  If *mem
    TRY
      x / MemorySize(*mem)
    ENDTRY
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

*mem = AllocateMemory(1024)
MyProc(*mem)
FreeMemory(*mem)
MyProc(*mem)
MessageRequester("Test", "Occurred after exception.")
Here is another example:

Code: Select all

Procedure SafePlace()
  MessageRequester("Warning", "An error has been encountered, and the application will be closed.")
  SetUnhandledExceptionFilter_(#Null)
  End
EndProcedure

Procedure UnhandledExceptionFilter(*ep.EXCEPTION_POINTERS)
  *ep\ExceptionRecord\ExceptionFlags = 0
  *ep\ContextRecord\Eip = @SafePlace()
  ProcedureReturn #EXCEPTION_CONTINUE_EXECUTION
EndProcedure
SetUnhandledExceptionFilter_(@UnhandledExceptionFilter())
RaiseException_(#EXCEPTION_ACCESS_VIOLATION, #EXCEPTION_NONCONTINUABLE, #Null, #Null)
SetUnhandledExceptionFilter_(#Null)

Re: Checking if memory is valid

Posted: Thu Apr 17, 2014 5:17 pm
by Thunder93
That version of code is Windows x86 platforms only.

Re: Checking if memory is valid

Posted: Thu Apr 17, 2014 5:35 pm
by Dreamland Fantasy
Thanks JHPJHP for those examples, but I need something that is going to be compatible across multiple platforms.

My current solution is to use a structure to store the memory pointer and other details, and check if these are valid. It seems to work, but I'll need to test it further to be sure that it will work in all cases.

Kind regards,

Francis