Announcement

Collapse
No announcement yet.

Prevent Crash, Invalid Parameter Passing

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Prevent Crash, Invalid Parameter Passing

    Am I able to avoid a GPF or other crash if someone passes an invalid value to my Function?

    For Example if I have a DLL and it appears as
    Code:
    DECLARE FUNCTION MyFunction(BYVAL MyNumber AS LONG) EXPORT AS LONG
    
    END FUNCTION
    If another programming language passes a +2,147,483,648 (1 one over the PB Long definition) can I do something like
    Code:
    DECLARE FUNCTION MyFunction(BYVAL MyNumber AS LONG) EXPORT AS LONG
         SELECT CASE MyNumber
              CASE > 2,147,483,64
              CASE < -2,147,483,648 
              CASE ELSE
                   MSGBOX "Invalid Parameter"
         END SELECT
    END FUNCTION
    or am I already hosed because the parameter was passed and its a matter of time that a GPF or other crash may or may not occur?

    Reason I ask is, all too often in my earlier days (and probably still now), me and a few others have always "Butted Heads" as to porting code from one language to another, and how it is DEFINITELY NOT "Verb for Verb" (aka a LONG my not mean a LONG in another programming language)

    Usually, its me trying to use someone else's DLL, but today its one where a user using Matlab calling my functions from MY DLL, but any function passing a parameter will cause a GPF or some error.

    I did some poking around and from what I can find, Although the value is a whole number, the definition of "LONG" allows for decimal points (so for all I know he could be passing 3.0 to me and not 3)

    From the bit I was able to look up from the 3rd party language, I could NOT find what the range of valid values were for them, but wonder if I can protect against this situation in my own dll?

    any ideas?, or am I at the whim of M$?.....to this day I have know CLUE as to when a error occurs (as we all know calling another dll, the problem may not creep up till later)
    Engineer's Motto: If it aint broke take it apart and fix it

    "If at 1st you don't succeed... call it version 1.0"

    "Half of Programming is coding"....."The other 90% is DEBUGGING"

    "Document my code????" .... "WHYYY??? do you think they call it CODE? "

  • #2
    Data types are defined by the compiler vendor, (not Microsoft), so when you write a function in PB that accepts a LONG, your function will receive a value that fits into that data type, as defined in the help file. It's the same with all variables - a BYTE is an easier example: when you define a BYTE as a parameter, PB will always give you a value between 0-255, even if the caller passes 256. Then (IIRC in the docs), the result is undefined, but in an experiment I noticed it "rolls over" to zero again (256=0, 257=1, and so on).

    I guess it boils down to what information is being passed. For handles and pointers, always use DWORD, and for values that can possibly be negative, use LONG. If you are writing a library to be called from a limited language like VB, you will have to expect any DWORD parameter to be converted from a LONG. For other languages it is even worse, as you found out. It would be perfectly possible to declare the value as a pointer and have an extra parameter defining the data type used.

    One thing that I am sure of though is that your app should never crash in normal operation(!), always check the value before using it.
    Last edited by Kev Peel; 7 Jun 2008, 03:06 AM.
    kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

    Comment


    • #3
      Your function will receive exactly 32 bits, which it will Interpret as a LONG integer. What 32 bits are passed is out of your control.. it is a function of the call syntax used by the using module.

      Any 32 bits you get will have "some value" when interpreted as a LONG.

      FWIW, LONG/DWORD in the procedure header is immaterial.. you still get 32 bits. Only if you do any arithmetic wth the value is the casting significant.

      Any 'crashing' you get here is NOT related to the casting of the parameter.

      It can be caused by bad point-of-call parameters. Eg if I called the above function using ...
      Code:
        DECLARE FUNCTION MyFunction (BYVAL C AS CURR) AS LONG
      
         hLib = LoadLibrary ("myDll.dll"
         dwAddr   =   GetProcAddress  (hLib, "MYFUNCTION") 
         CALL DWORD dwAddr USING myFunction (Currency_var) TO resultvar 
        ..
      .. you'd get a crash, since the call is pushing 8 bytes onto the stack, but MyFunction thinks it is only getting four bytes.
      Michael Mattias
      Tal Systems (retired)
      Port Washington WI USA
      [email protected]
      http://www.talsystems.com

      Comment


      • #4
        Thanx guys,
        I kinda figured that, but I stuck with DWORD vs Long because 32 bits is 32 bits, nomatter what you call it.

        I guess my better question would be, if someone passes me the 32bits, can I check and handle that value before the offending crash or GPF??? (My guess would be yes, because it is up to me the programmer to not allow invalid values to be operated on, and NOT up to the operating system. But just wanted to verify

        In the case of the 3rd party language, the original "Header" file I produced for earlier versions, used "Long" (as in PB definition of LONG) in the header. And all was fine until the latest version of Matlab (yet to find out if Matlab changed something or what it was that changed....but anyyyyyways)

        In this type of scenario, shouldn't the offending "crash" or GPF only occur if under one of the following conditions (if I read the docs correctly)
        • I was passed either a value outside the range of -2,147,483,64 to 2,147,483,64
        • I was passed a "non-whole-number" somewhere between -2,147,483,64 to 2,147,483,64
        • I was passed a value less than 32 bits wide....(don't think this would happen because 32 bits is larger than less bits)
        • Passed a value more than 32 bits wide....(likely to happen because 32 can not hold 64 bit value) and would be "over-stuffed" I would think)

        In any case, should I not be allowed to test for valid values, and warn for invalid and prevent the "Crash/GPF" from even occuring?????
        Engineer's Motto: If it aint broke take it apart and fix it

        "If at 1st you don't succeed... call it version 1.0"

        "Half of Programming is coding"....."The other 90% is DEBUGGING"

        "Document my code????" .... "WHYYY??? do you think they call it CODE? "

        Comment


        • #5
          I guess we don't have enough information to help you further. What is the code doing with the value? If it is a memory location or code pointer it is easy to check for validity with the API functions IsBadReadPtr, IsBadWritePtr and IsBadCodePtr, IsWindow for a window handle, INVALID_HANDLE_VALUE or NULL for a null-pointer, etc.

          A 32-bit parameter will always contain 32-bits of data, even if you try to pass a larger or smaller value or variable. Only the 32-bits of the value (the low part) will get passed, or padded if the value is less than 32-bits. If your code expects a DWORD, but is passed -1, you get something like &HFFFFFFFF??? (the highest range of a DWORD variable).

          Really, even with the functions I mentioned above, there is no "magic" solution to ensure the value is correct, as the pointer/handle address could be valid to the process, but not for what is intended. The onus is really on the caller of your DLL to get it right, and as such is not your problem - you can never, ever, make a program or library completely foolproof
          kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

          Comment


          • #6
            Thanx Kev,
            That is EXACTLY what I was looking for. I had forgotten about the "IsBad" pointer functions.

            Unfortunately for me, 99% of my customer base has little to no programming experience. (Usually some student needing to move a stepper motor to a position so they can take a reading with some other device).

            Colleges seem to go with MatLab or Labview (Personally I have no idea why, since to me neither one are a "Programming Language" but more a "Here is how to program, without knowing how to program" situation).
            Which is why I went from VB to PB and built an easy to use DLL to control all the serial port communications, and "Bullet-Proof" as much as I possibly can

            I would rather not have to re-write, or write a new version for some language I do not know well enough (nor want to) when PB does all that I need, and a long passed a value of "4" is valid no matter what because it is in the range, and is within 32 bits.

            Thanks to you guys, I now see that although I can not 100% bullet proof, I can sure as heck try and will have to get more info from the user(s) to determine what (if) there is a flaw in my code that has been running on thousands of machines for the last 5 years and just now causing problems???

            Even without the Failing code, you guys gave me ideas where I can look and what I can do about it. Thank you again for your input and ideas
            Engineer's Motto: If it aint broke take it apart and fix it

            "If at 1st you don't succeed... call it version 1.0"

            "Half of Programming is coding"....."The other 90% is DEBUGGING"

            "Document my code????" .... "WHYYY??? do you think they call it CODE? "

            Comment

            Working...
            X