Announcement

Collapse
No announcement yet.

VARPTR problem

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

  • VARPTR problem

    i am trying to use varptr to check to see if the pointer for an
    asciiz string argument is null, but using varptr itself with the
    null string causes an error. here's what i did:

    Code:
    $compile exe
    $debug error on
    
    sub test(asciizarg as asciiz)
       if varptr(asciizarg) = 0 then temp$ = " else temp$ = asciizarg
    
       msgbox str$(err) ' returns error #9
    end sub
    
    function pbmain as long
       call test(")
    end function
    in another forum message, asciiz empty..., i explained the problem
    i was having. i was given the solution of checking the asciiz
    argument for null before using it, to avoid a crash later on.
    after praising the solution, i tried it again later, and it
    didn't work. my last response there may have gone unoticed, so
    i'm posting this in a new thread hoping to find another way
    around this problem.

    basically the situation is that there's a sub which takes
    an asciiz argument. i want to avoid the gpf that can happen if
    an empty string is passed to that routine.

    ------------------
    daniel corbier
    ucalc fast math parser
    http://www.ucalc.com
    Daniel Corbier
    uCalc Fast Math Parser
    uCalc Language Builder
    sigpic

  • #2
    Code:
    If IsBadStringPtr(AsciizArg,2048&) = %NULL Then
      Tmp$ = AsciizArg
    Else
      Tmp$ = ""
    End if

    ------------------
    Fred
    mailto:[email protected][email protected]</A>
    http://www.oxenby.se

    Fred
    mailto:[email protected][email protected]</A>
    http://www.oxenby.se

    Comment


    • #3
      Code:
      $Compile Exe
      $Debug Error On
      Sub Test(AsciizArg As Asciiz Ptr)
         If AsciizArg = 0 Then Temp$ = "" Else Temp$ = @AsciizArg
         MsgBox "Err = " + Str$(Err),, "Temp$ = " + $DQ + Temp$ + $DQ
      End Sub
      Function PbMain As Long
         Call Test("Test #1")
         Call Test("")
      End Function

      ------------------
      E-MAIL: [email protected]

      Comment


      • #4
        Dan --

        Keep in mind that there is a difference between passing a nul string and a nul pointer. For example, if you pass an ASCIIZ string that has a length of zero, you are actually passing a valid pointer to a memory location, but when Windows looks there it will find CHR$(0), indicating end-of-string. But if instead of a string you pass BYVAL 0 (thereby overriding PB's automatic parameter checking) if your function checks VARPTR it will see zero. A nul pointer, not a pointer to a nul string.

        You probably want to check for VARPTR(zString)=0 first. Then, only if it is nonzero, check for LEN(zString) = 0.

        [Added later]

        Hmmm... I just tried my own advice about VARPTR and I didn't get the results I expected. But it does look like testing LEN=0 will work.

        -- Eric


        ------------------
        Perfect Sync Development Tools
        Perfect Sync Web Site
        Contact Us: mailto:[email protected][email protected]</A>



        [This message has been edited by Eric Pearson (edited May 23, 2001).]
        "Not my circus, not my monkeys."

        Comment


        • #5
          I was wrong, I mean I was right...

          I am in fact seeing VARPTR=0 when "" is passed, as well as when BYVAL 0 is passed.

          What is the problem that you are trying to overcome? Are you concerned about the ERR 9?

          -- Eric



          ------------------
          Perfect Sync Development Tools
          Perfect Sync Web Site
          Contact Us: mailto:[email protected][email protected]</A>
          "Not my circus, not my monkeys."

          Comment


          • #6
            Guys thanks for the responses.

            Eric, yes, error #9 is my concern. I was getting a mysterious
            crash. I gradually narrowed it down, keeping an eye on arrays.
            But the culprit was a line where an empty ASCIIZ argument was
            used. The thing with these types of errors is that they remain
            silent, and crash somewhere else in the program, making it
            very hard to track.

            Fred, I'm not familiar with IsBadStringPtr(). I didn't see
            it in the help file. I searched and found it in the API, but
            with no explanation of how it works.

            Semen, I tried your solution (passing the arg as an ASCIIZ PTR),
            and it seems to work so far. I tried it with PB, VB, and Delphi.
            Since it works with Delphi, I assume that it will work with
            C++ as well. But I'll have to try it more extensively later on
            to make sure.

            Now that the problem appears to be solved, I still wonder why
            PB returns an error for VARPTR of an empty ASCIIZ string. This
            doesn't appear normal. Maybe R&D should look into it, and fix it
            if it's a bug. To me, it seems like "If VARPTR(AsciizArg) = 0 ..."
            should work just as well as "If AsciizPtrArg = 0 ...". The
            documentation discusses the usage of ASCIIZ arguments. It
            mentions necessary precautions when modifying the argument, but
            it doesn't say (at least where I was looking) anything about
            potential problems with accessing an empty ASCIIZ string arg.

            The program in the Sample\VB32 directory (CAPFIRST.BAS) would
            also need to be updated so that it can safely handle an empty
            string, since others might pattern their DLLs after that
            example.

            ------------------
            Daniel Corbier
            UCalc Fast Math Parser
            http://www.ucalc.com
            Daniel Corbier
            uCalc Fast Math Parser
            uCalc Language Builder
            sigpic

            Comment


            • #7
              Daniel,

              If you wish to test if an ASCIIZ string is a NULL string, just read
              the 1st byte of the string and see if its ascii zero.

              Without testing it, I would be inclined to try,
              Code:
                  If left$(asciizString,1) = chr$(0) Then
                    ' code here
                  End If
              Regards,

              [email protected]

              ------------------
              hutch at movsd dot com
              The MASM Forum

              www.masm32.com

              Comment


              • #8
                I experianced the same when i used a PB exe using PB dll.
                VB will allways use a valid address even when empty.

                I test this using:

                If Clng( VarPtr( az ) ) Then

                End If

                Maybe Clng() makes a difference here.


                ------------------
                hellobasic

                Comment


                • #9
                  Since VARPTR is returning zero, the CLNG is simply converting a long integer result into a long integer result...

                  Eric summed it up here... In Daniels original code, VARPTR returns zero, and for good measure, ERR is set to reflect that a null string was passed.

                  Where is the problem?



                  ------------------
                  Lance
                  PowerBASIC Support
                  mailto:[email protected][email protected]</A>
                  Lance
                  mailto:[email protected]

                  Comment


                  • #10
                    Originally posted by Daniel Corbier:
                    Guys thanks for the responses.
                    Fred, I'm not familiar with IsBadStringPtr(). I didn't see
                    it in the help file. I searched and found it in the API, but
                    with no explanation of how it works.
                    Parameters
                    lpsz [in] Pointer to a null-terminated string, either Unicode or ASCII.
                    ucchMax [in] Specifies the maximum size, in TCHARs, of the string. The function checks for read access
                    in all bytes up to the string's terminating null character or up to the number of bytes specified by this parameter,
                    whichever is smaller. If this parameter is zero, the return value is zero.

                    Return Values
                    If the calling process has read access to all characters up to the string's terminating null character
                    or up to the number of characters specified by ucchMax, the return value is zero.

                    If the calling process does not have read access to all characters up to the string's terminating null character
                    or up to the number of characters specified by ucchMax, the return value is nonzero.

                    If the application is compiled as a debugging version, and the process does not have read access to the entire memory range specified,
                    the function causes an assertion and breaks into the debugger. Leaving the debugger, the function continues as usual,
                    and returns a nonzero value This behavior is by design, as a debugging aid.

                    Remarks
                    This function is typically used when working with pointers returned from third-party libraries, where you cannot determine
                    the memory management behavior in the third-party DLL.

                    Threads in a process are expected to cooperate in such a way that one will not free memory that the other needs.
                    Use of this function does not negate the need to do this. If this is not done, the application may fail in an unpredictable manner.

                    Dereferencing potentially invalid pointers can disable stack expansion in other threads. A thread exhausting its stack,
                    when stack expansion has been disabled, results in the immediate termination of the parent process,
                    with no pop-up error window or diagnostic information.

                    If the calling process has read access to some, but not all, of the specified memory range, the return value is nonzero.

                    In a preemptive multitasking environment, it is possible for some other thread to change the process's access to the memory being tested.
                    Even when the function indicates that the process has read access to the specified memory, you should use structured exception handling
                    when attempting to access the memory. Use of structured exception handling enables the system to notify the process
                    if an access violation exception occurs, giving the process an opportunity to handle the exception.

                    ------------------
                    Fred
                    mailto:[email protected][email protected]</A>
                    http://www.oxenby.se

                    Fred
                    mailto:[email protected][email protected]</A>
                    http://www.oxenby.se

                    Comment


                    • #11
                      Daniel, I would go with what Semen suggested (pass the address of the asciiz string and check if it is <=0)
                      Or similarly to what Steve suggested - just check the ascii value of the asciiz string if you pass the string.

                      Comment


                      • #12
                        Steve and Ron's advice is incorrect I'm afraid... the terminating byte in an ASCIIZ string is not "part" of the string as far as the string engine is concerned, so a test like:
                        Code:
                        If left$(asciizString,1) = chr$(0) Then...
                        will never be satisfied!!!

                        To reiterate, if the function is expecting an ASCIIZ, and you pass BYVAL 0& or just "", then VARPTR in the function will return 0... the invalid pointer is identified clearly.

                        Finally, regarding the VARPTR result - Ron mentions testing for "<=0", however, if you assign the VARPTR to a signed (LONG) integer, the test for an invalid pointer will fail INCORRECTLY, since a negative value is still a valid 32-bit address (just interpreted as a signed value).


                        ------------------
                        Lance
                        PowerBASIC Support
                        mailto:[email protected][email protected]</A>
                        Lance
                        mailto:[email protected]

                        Comment


                        • #13
                          Eric summed it up here... In Daniels original code, VARPTR returns zero, and for good measure, ERR is set to reflect that a null string was passed.

                          Where is the problem?
                          There are two problems. 1. GPFs. 2. Complications in error
                          handling.

                          When I was getting the GPF, I added debug code gradually until it
                          lead me to that line.

                          Even in the absence of a GPF error, when ERR is set unnecessarily,
                          it disrupts the program flow. ON ERROR GOTO jumps to a label, but
                          I can't jump back automatically.

                          WISHLIST Item: Please add support for RESUME NEXT.

                          If passing a null ASCIIZ string is illegal, then it should be
                          clearly documented. If it's not illegal, then ERR should not be
                          set. This only gets in the way.

                          Also, bugs which lead to error 9 typically lead to GPFs. That's
                          why I suggest that R&D check to see whether whatever's triggering
                          ERR 9 in this context might not also be corrupting memory causing
                          a GPF. The problem might originate from elsewhere, but I don't
                          think it hurts to double check.

                          ------------------
                          Daniel Corbier
                          UCalc Fast Math Parser
                          http://www.ucalc.com
                          Daniel Corbier
                          uCalc Fast Math Parser
                          uCalc Language Builder
                          sigpic

                          Comment


                          • #14
                            IMHO, these are mainly programming issues, not compiler issues. FOr example, if you are writing a commercial DLL and you do not adequately test the pointer being received from someone else's program (which is completely beyond your control), you are asking for problems. If your code GPF's, then you did NOT test the pointer adequately. Afterall, it is not up to PowerBASIC to decide what is and what is not a valid pointer in this circumstance...

                            However, I'll still pass your comments along to R&D... Thanks!


                            ------------------
                            Lance
                            PowerBASIC Support
                            mailto:[email protected][email protected]</A>
                            Lance
                            mailto:[email protected]

                            Comment


                            • #15
                              Daniel,

                              It seems to me that your problem occured because the parameter you passed
                              did not agree with what was expected in the sub. You passed a null string
                              and the sub expected a string ending with chr$(0). Therefore, you must
                              call test("" + chr$(0)). And the SUB should test with LEN, not VARPTR.

                              So, your code should be:

                              Code:
                              $COMPILE EXE
                              $DEBUG ERROR ON
                              SUB Test(AsciizArg AS ASCIIZ)
                                 IF LEN(AsciizArg) = 0 THEN Temp$ = "" ELSE Temp$ = AsciizArg
                                 MSGBOX STR$(ERR) 'Returns 0 now
                              END SUB
                              FUNCTION PBMAIN AS LONG
                                 CALL Test("" + CHR$(0))
                              END FUNCTION
                              I don't really know why Semen's solution seemed to work.


                              ------------------

                              Comment


                              • #16
                                Lance, you should re-read my message. I suggested checking the ascii value of the asciiz string and did not mention checking for chr$(0). Also, checking to see if the pointer (casted to a long) is <=0 will work fine unless you have more than 2gb ram. Of course, <> 0 will work in all cases and I should have stated that instead of <= 0.

                                DON'T assign a pointer to a long integer if you have > 2GB ram. If you look at Semen's message - he is suggesting checking the value of a pointer - not a long. At any rate a pointer with a value of 0 is a null pointer.

                                If the ascii value of a string = -1 then it is an empty string. I had thought it would be 0 for an asciiz string without testing this. Asciiz and dynamic strings both report -1 for the ascii value if the string is empty.






                                Comment


                                • #17
                                  No, it is you who have misread my message. The CHR$(0) comment comes from Steve's message, and the "<=0" comments stem from your advice.

                                  I find your comments about the importance of having more than 2G of physical RAM interesting. In truth, physical RAM is not a factor in these discussions. Remember, some Win32 platforms can actually provide up to 3Gb of virtual memory for a given process.

                                  However, my point was that you have to be careful when making assumptions about signed/unsigned comparisons. In this context, any advice that suggests checking "<=0" to determine if a pointer is invalid is flawed advice. Sorry!

                                  ------------------
                                  Lance
                                  PowerBASIC Support
                                  mailto:[email protected][email protected]</A>
                                  Lance
                                  mailto:[email protected]

                                  Comment


                                  • #18
                                    Charles, I gave your idea a quick try, and it seems like a
                                    possible alternative as well. You're right, I don't see why
                                    Semen's method worked that way, while the other method which is
                                    similar did not. Both should yield a similar result. But I'm
                                    thankful that R&D will look into it.

                                    Anyway, I spent today looking into this some more, and based on
                                    what I read in the MSDN, I see that PB is interpreting VB zero-
                                    length strings incorrectly. A zero-length VB string has a valid
                                    non-null address. When a VB program needs to pass an actual null
                                    string to an API as opposed to "", this is done by passing
                                    vbNullString. However, when "" is passed from VB to PB's ASCIIZ
                                    argument, the "" is incorrectly interpreted the same as
                                    vbNullString. (Looking back I see that Eric's original
                                    message started explaining how things should work. But then he
                                    tried it in PB and ...

                                    I tested zero-length strings with C++ and Delphi, and I saw
                                    that in those compilers the pointer to a zero-length string ("")
                                    is not 0. The string pointer has a valid address, and the byte
                                    at that location is chr$(0). Furthermore, when I pass a "" string
                                    from VB to a Delphi DLL function which takes a null-terminated
                                    string argument (PChar), the pointer has a valid non-zero address.
                                    So it seems like PB is actually doing an extra step to convert
                                    the valid zero-length string it receives into a zero-address pointer.

                                    So I'd like to request that PB not convert zero length ASCIIZ
                                    arguments to NULL (whether it's from a call within PB or from VB).
                                    My guess is that it was done this way to match VB 3.0, which did
                                    not yet have a direct way of distinguishing a zero-length string
                                    from a null-string. Other than matching VB 3.0, I can see no
                                    other practical reason for not separating the two.

                                    After testing things, it turns out that all of this may have had
                                    nothing to do with the original GPF. Apparently ERR 9 in this
                                    context only masked a different problem. ERR 9, which was
                                    triggered at the ASCIIZ line diverted the code to the "On Error"
                                    label, skipping necessary code, and crashing. "IF VARPTR" did not
                                    do any better, since it set ERR 9 just the same. Later, I was
                                    not satisfied, to see the error mysteriously disappear when I
                                    disabled "Debug Error", and removed the "IF VARPTR" line. So I
                                    checked source code from a few weeks back, and realized that I
                                    in the process of debugging, I had also fixed some code which
                                    was calling itself recursively and running out of stack. This
                                    only goes to show how a global error handler would be more
                                    accurate in tracking such tricky errors (instead of manually
                                    inserting error handlers in functions where you think the problems
                                    might be located).

                                    I have another problem. A global error-handling routine is ideal.
                                    However, I've noticed that ERR is listed in the debugger watch
                                    window. I'd settle with that for now, however, no matter what I
                                    do to induce an error, ERR always displays 0. Am I using it
                                    the wrong way, or is it a bug? Also, it seems like bad pointer
                                    references aren't caught by On Error Goto at all (it just crashes).

                                    Here's a problem of a different nature that I noticed just
                                    recently in the IDE. If I load a long program, and as soon
                                    as it's loaded, I scroll all the way to the bottom with the
                                    mouse, using the scroll-bar on the right, and then I hold
                                    my hand on PgUp, to scroll back up, it crashes the IDE.


                                    ------------------
                                    Daniel Corbier
                                    UCalc Fast Math Parser
                                    http://www.ucalc.com
                                    Daniel Corbier
                                    uCalc Fast Math Parser
                                    uCalc Language Builder
                                    sigpic

                                    Comment


                                    • #19
                                      1. vbNullString... I'll have to ask R&D about that one.

                                      2. Global error trap... Personally I don't see how that particular (although unusual) situation could justify the addition of a global error trapping. Since the effect was a crash or GPF, how would a global error trap actually tell you that you acidentally created a recursive call any more than a local error trap would? Analysing the call stack would be much more effective, and you can do this within the sub/function code quite simply.

                                      3. ERR in the debugger... Long since confirmed as a bug.

                                      4. The IDE GPF has also been reported on this BBS a few times.

                                      #3 and #4 are expected to be corrected in the next update...



                                      ------------------
                                      Lance
                                      PowerBASIC Support
                                      mailto:[email protected][email protected]</A>
                                      Lance
                                      mailto:[email protected]

                                      Comment


                                      • #20
                                        #2 Global Error trap

                                        I'm not a fan of the global error trap approach. A better
                                        approach would be to settle for SEH (Structured Exception
                                        Handling) with TRY, EXCEPT, etc constructs.

                                        This would have enabled you to trap the gpf and take
                                        appropriate action.


                                        Cheers

                                        Florent


                                        ------------------

                                        Comment

                                        Working...
                                        X