Loading ...
Sorry, an error occurred while loading the content.

What a to-do!

Expand Messages
  • Walter Briscoe
    ... I built a console vim with Make_ivc.mak. I tried vim -u NONE -U NONE shrtname. vim started as if I had done vim -u NONE -U NONE long file name . This
    Message 1 of 15 , Oct 3, 2002
    • 0 Attachment
      I quote from the vim 6.1.1-100 todo.txt:
      > Win32 console:
      > 9 When editing a file by its short file name, it should be expanded into its
      > long file name, to avoid problems like these: (Mccollister)
      > 1) Create a file called ".bashrc" using some other editor.
      > 2) Drag that file onto a shortcut or the actual executable.
      > 3) Note that the file name is something like BASHRC~1
      > 4) Go to File->Save As menu item and type ".bashrc" as the file name.
      > 5) Press "Yes" to indicate that I want to overwrite the file.
      > 6) Note that the message "File exists (use ! to override)" is displayed
      > and the file is not saved.
      > Use FindFirstFile() to expand a file name and directory in the path to its
      > long name.

      I built a console vim with Make_ivc.mak.
      I tried vim -u NONE -U NONE shrtname. vim started as if I had done
      vim -u NONE -U NONE "long file name". This happened in both WME and W95.
      I shall try the precise problem reported on W95.
      1) done (echo hello > .bashrc)
      2) Dragged
      3) File name is .bashrc rather than BASHRC~1 or similar
      4) No file menu. I think this MIGHT refer to gvim
      3a) File name is C:\TEMP\BASHRC~1
      4a) File-Save default name is .bashrc. No override needed.

      Is there any problem?

      > 8 ":winpos" doesn't work. Patch from Vipin Aravind.
      It works for me in gvim. It does not work in vim. Why should it do so?
      It is documented as:
      > :winp[os]
      > Display current position of the top left corner of the GUI vim
      > window in pixels. Does not work in all versions.

      I shall look at:
      > 9 When using libcall() for a function that returns an invalid pointer, Vim
      > crashes. Check for a bad pointer with isBadReadPtr() doesn't appear to
      > work well.
      Steve Oualline's book does not mention libcall. I see it is mentioned in
      version5.txt as a contribution from Negri. Perhaps Vince can get me up
      to speed with a demonstration of the feature. It must be useful as it
      was originally implemented only in Win32 and is now also done in UNIX.
      --
      Walter Briscoe
    • Bram Moolenaar
      ... I suppose this is actually for gvim. ... Either it depends on the version of MS-Windows or it was already fixed. In win98 I do get a message about editing
      Message 2 of 15 , Oct 3, 2002
      • 0 Attachment
        Walter Briscoe wrote:

        > I quote from the vim 6.1.1-100 todo.txt:
        > > Win32 console:
        > > 9 When editing a file by its short file name, it should be expanded into its
        > > long file name, to avoid problems like these: (Mccollister)
        > > 1) Create a file called ".bashrc" using some other editor.
        > > 2) Drag that file onto a shortcut or the actual executable.
        > > 3) Note that the file name is something like BASHRC~1
        > > 4) Go to File->Save As menu item and type ".bashrc" as the file name.
        > > 5) Press "Yes" to indicate that I want to overwrite the file.
        > > 6) Note that the message "File exists (use ! to override)" is displayed
        > > and the file is not saved.
        > > Use FindFirstFile() to expand a file name and directory in the path to its
        > > long name.
        >
        > I built a console vim with Make_ivc.mak.
        > I tried vim -u NONE -U NONE shrtname. vim started as if I had done
        > vim -u NONE -U NONE "long file name". This happened in both WME and W95.
        > I shall try the precise problem reported on W95.
        > 1) done (echo hello > .bashrc)
        > 2) Dragged
        > 3) File name is .bashrc rather than BASHRC~1 or similar
        > 4) No file menu. I think this MIGHT refer to gvim

        I suppose this is actually for gvim.

        > 3a) File name is C:\TEMP\BASHRC~1
        > 4a) File-Save default name is .bashrc. No override needed.
        >
        > Is there any problem?

        Either it depends on the version of MS-Windows or it was already fixed.
        In win98 I do get a message about editing BASHRC~1, but the buffer name
        is .bashrc. That means the conversion to a long filename was already
        done.

        > > 8 ":winpos" doesn't work. Patch from Vipin Aravind.
        > It works for me in gvim. It does not work in vim. Why should it do so?
        > It is documented as:
        > > :winp[os]
        > > Display current position of the top left corner of the GUI vim
        > > window in pixels. Does not work in all versions.

        It also works for an xterm. If there is a way to make it work in a
        console window, why not do it?

        > I shall look at:
        > > 9 When using libcall() for a function that returns an invalid pointer, Vim
        > > crashes. Check for a bad pointer with isBadReadPtr() doesn't appear to
        > > work well.
        > Steve Oualline's book does not mention libcall. I see it is mentioned in
        > version5.txt as a contribution from Negri. Perhaps Vince can get me up
        > to speed with a demonstration of the feature. It must be useful as it
        > was originally implemented only in Win32 and is now also done in UNIX.

        It would be good if you can fix this. I did an attempt once, but
        couldn't find a way to avoid a crash. Best is if any use of libcall()
        detects that a pointer is not valid and gives an error message instead
        of crashing.

        --
        Nobody will ever need more than 640 kB RAM.
        -- Bill Gates, 1983
        Windows 98 requires 16 MB RAM.
        -- Bill Gates, 1999
        Logical conclusion: Nobody will ever need Windows 98.

        /// Bram Moolenaar -- Bram@... -- http://www.moolenaar.net \\\
        /// Creator of Vim - Vi IMproved -- http://www.vim.org \\\
        \\\ Project leader for A-A-P -- http://www.a-a-p.org ///
        \\\ Lord Of The Rings helps Uganda - http://iccf-holland.org/lotr.html ///
      • Bruce Mellows
        I might be able to contribute a bit here. I have hard won knowledge of how to (correctly) continue execution after a GPF on Win32. From reading :help
        Message 3 of 15 , Oct 3, 2002
        • 0 Attachment
          I might be able to contribute a bit here.

          I have hard won knowledge of how to (correctly) continue execution after
          a GPF on Win32.

          From reading :help libcall(), I assume that the function that returns a
          string has returned a non-null, invalid pointer, so you would only need
          to protect the function that converts the returned pointer into a string.

          Perhaps it would be best to discuss this off the list ???

          Bruce

          Bram Moolenaar wrote:

          >Walter Briscoe wrote:
          >
          >
          >
          >>I shall look at:
          >>
          >>
          >>>9 When using libcall() for a function that returns an invalid pointer, Vim
          >>> crashes. Check for a bad pointer with isBadReadPtr() doesn't appear to
          >>> work well.
          >>>
          >>>
          >>Steve Oualline's book does not mention libcall. I see it is mentioned in
          >>version5.txt as a contribution from Negri. Perhaps Vince can get me up
          >>to speed with a demonstration of the feature. It must be useful as it
          >>was originally implemented only in Win32 and is now also done in UNIX.
          >>
          >>
          >
          >It would be good if you can fix this. I did an attempt once, but
          >couldn't find a way to avoid a crash. Best is if any use of libcall()
          >detects that a pointer is not valid and gives an error message instead
          >of crashing.
          >
          >
          >
        • Walter Briscoe
          In article of Thu, 3 Oct 2002 20:06:52 in , Bram Moolenaar writes ... [snip] ... Thanks to Vince
          Message 4 of 15 , Oct 6, 2002
          • 0 Attachment
            In article <200210031806.g93I6qu02401@...> of Thu, 3 Oct 2002
            20:06:52 in , Bram Moolenaar <Bram@...> writes
            >
            >Walter Briscoe wrote:
            >
            [snip]
            >> I shall look at:
            >> > 9 When using libcall() for a function that returns an invalid
            >> >pointer, Vim
            >> > crashes. Check for a bad pointer with isBadReadPtr() doesn't appear to
            >> > work well.
            >> Steve Oualline's book does not mention libcall. I see it is mentioned in
            >> version5.txt as a contribution from Negri. Perhaps Vince can get me up
            >> to speed with a demonstration of the feature. It must be useful as it
            >> was originally implemented only in Win32 and is now also done in UNIX.
            >
            >It would be good if you can fix this. I did an attempt once, but
            >couldn't find a way to avoid a crash. Best is if any use of libcall()
            >detects that a pointer is not valid and gives an error message instead
            >of crashing.
            >

            Thanks to Vince Negri for a DLL. I did manage to produce a crash in that
            DLL when I miscalled a function. I did not manage to crash vim itself.
            It may be reasonable to use Bruce Mellows protection against a GPF in a
            dll. Can you please email me a copy, Bruce? For reasons I have not
            diagnosed, let &ts=libcall... sets &ts to '8'.
            --
            Walter Briscoe
          • Walter Briscoe
            In article of Thu, 3 Oct 2002 20:06:52 in , Bram Moolenaar writes ... [snip] ... I set up a test
            Message 5 of 15 , Oct 7, 2002
            • 0 Attachment
              In article <200210031806.g93I6qu02401@...> of Thu, 3 Oct 2002
              20:06:52 in , Bram Moolenaar <Bram@...> writes
              >
              >Walter Briscoe wrote:
              >
              [snip]
              >> > 8 ":winpos" doesn't work. Patch from Vipin Aravind.
              >> It works for me in gvim. It does not work in vim. Why should it do so?
              >> It is documented as:
              >> > :winp[os]
              >> > Display current position of the top left corner of
              >> >the GUI vim
              >> > window in pixels. Does not work in all versions.
              >
              >It also works for an xterm. If there is a way to make it work in a
              >console window, why not do it?

              I set up a test program. It produces the same results as Spy++ on W2K.
              It produces plausible results in W95. When it runs in full screen mode,
              it produces implausible results. (-32000, -32000) in W2K, (3000, 3000)
              in W95. Is this behaviour adequate?

              #pragma warning(disable: 4100 4115 4201 4214 4514)
              #include <windows.h>
              #pragma warning(default: 4100 4115 4201 4214)
              #include <stdio.h>

              HWND s_hwnd = NULL;
              int
              gui_mch_get_winpos(int *x, int *y)
              {
              RECT rect;

              GetWindowRect(s_hwnd, &rect);
              *x = rect.left;
              *y = rect.top;
              return 0;
              }

              int main(void) {
              int x, y;

              s_hwnd = GetForegroundWindow();
              (void)gui_mch_get_winpos(&x, &y);

              printf("x = %d, y = %d\n", x, y);
              return 0;
              }


              --
              Walter Briscoe
            • Bram Moolenaar
              ... Looks like you need to test for full-screen mode and force returning (0, 0). In full-screen mode you might also want to explicitly ignore changing the
              Message 6 of 15 , Oct 7, 2002
              • 0 Attachment
                Walter Briscoe wrote:

                > I set up a test program. It produces the same results as Spy++ on W2K.
                > It produces plausible results in W95. When it runs in full screen mode,
                > it produces implausible results. (-32000, -32000) in W2K, (3000, 3000)
                > in W95. Is this behaviour adequate?

                Looks like you need to test for full-screen mode and force returning
                (0, 0). In full-screen mode you might also want to explicitly ignore
                changing the window position.

                --
                hundred-and-one symptoms of being an internet addict:
                136. You decide to stay in a low-paying job teaching just for the
                free Internet access.

                /// Bram Moolenaar -- Bram@... -- http://www.moolenaar.net \\\
                /// Creator of Vim - Vi IMproved -- http://www.vim.org \\\
                \\\ Project leader for A-A-P -- http://www.a-a-p.org ///
                \\\ Lord Of The Rings helps Uganda - http://iccf-holland.org/lotr.html ///
              • Bruce Mellows
                This is the code to protect a function from a GPF. NOTE... - The critical part of the work *MUST* be done in assembler - so I decided that it might be best if
                Message 7 of 15 , Oct 7, 2002
                • 0 Attachment
                  This is the code to protect a function from a GPF.

                  NOTE...

                  - The critical part of the work *MUST* be done in assembler - so I
                  decided that it might be best if it was ALL in assembler - so it can be
                  in one place (the actual exception handler could have been done in less
                  than ten lines of C).

                  - The assembler used is nasm - I could re-write it in masm if that was
                  preferred.

                  - The (example) mk.bat assumes a correct environment to run both the
                  nasm assembler and the bcc32 compiler.

                  - There is a void pointer in the prototype for the protected function -
                  obviously this can be replaced with a single safely typed parameter -
                  the assembler just passes one (32bit) parameter along from caller to callee.

                  CREDIT...

                  - Check out www.godevtool.com if you want to know more (I spoke to the
                  author of this site, and he said that is was OK to disseminate this
                  knowledge, but would appreciate the web site being mentioned - and here
                  it is).

                  HTH

                  Bruce.

                  Walter Briscoe wrote:

                  >In article <200210031806.g93I6qu02401@...> of Thu, 3 Oct 2002
                  >20:06:52 in , Bram Moolenaar <Bram@...> writes
                  >
                  >
                  >>Walter Briscoe wrote:
                  >>
                  >>
                  >>
                  >[snip]
                  >
                  >
                  >>>I shall look at:
                  >>>
                  >>>
                  >>>>9 When using libcall() for a function that returns an invalid
                  >>>>pointer, Vim
                  >>>> crashes. Check for a bad pointer with isBadReadPtr() doesn't appear to
                  >>>> work well.
                  >>>>
                  >>>>
                  >>>Steve Oualline's book does not mention libcall. I see it is mentioned in
                  >>>version5.txt as a contribution from Negri. Perhaps Vince can get me up
                  >>>to speed with a demonstration of the feature. It must be useful as it
                  >>>was originally implemented only in Win32 and is now also done in UNIX.
                  >>>
                  >>>
                  >>It would be good if you can fix this. I did an attempt once, but
                  >>couldn't find a way to avoid a crash. Best is if any use of libcall()
                  >>detects that a pointer is not valid and gives an error message instead
                  >>of crashing.
                  >>
                  >>
                  >>
                  >
                  >Thanks to Vince Negri for a DLL. I did manage to produce a crash in that
                  >DLL when I miscalled a function. I did not manage to crash vim itself.
                  >It may be reasonable to use Bruce Mellows protection against a GPF in a
                  >dll. Can you please email me a copy, Bruce? For reasons I have not
                  >diagnosed, let &ts=libcall... sets &ts to '8'.
                  >
                  >
                • Bram Moolenaar
                  ... Bummer. I do like the protection against crashes, but using assembly makes it very difficult to compile Vim on various platforms (64 bit anyone?). It
                  Message 8 of 15 , Oct 8, 2002
                  • 0 Attachment
                    Bruce Mellows wrote:

                    > This is the code to protect a function from a GPF.
                    >
                    > NOTE...
                    >
                    > - The critical part of the work *MUST* be done in assembler - so I
                    > decided that it might be best if it was ALL in assembler - so it can be
                    > in one place (the actual exception handler could have been done in less
                    > than ten lines of C).
                    >
                    > - The assembler used is nasm - I could re-write it in masm if that was
                    > preferred.

                    Bummer. I do like the protection against crashes, but using assembly
                    makes it very difficult to compile Vim on various platforms (64 bit
                    anyone?).

                    It appears your code also catches a crash in the called function. That
                    was not really required. Would it be possible to avoid the assembly
                    code when we only want to check the returned pointer? There actually is
                    a function for this (to check the validity of a pointer), but I couldn't
                    make it work.

                    --
                    hundred-and-one symptoms of being an internet addict:
                    161. You get up before the sun rises to check your e-mail, and you
                    find yourself in the very same chair long after the sun has set.

                    /// Bram Moolenaar -- Bram@... -- http://www.moolenaar.net \\\
                    /// Creator of Vim - Vi IMproved -- http://www.vim.org \\\
                    \\\ Project leader for A-A-P -- http://www.a-a-p.org ///
                    \\\ Lord Of The Rings helps Uganda - http://iccf-holland.org/lotr.html ///
                  • Bruce Mellows
                    Without the example of the GPF (so please forgive my assumptions, if they are wrong)... I have written two functions - safe_strlen and safe_strcpy (and a main
                    Message 9 of 15 , Oct 8, 2002
                    • 0 Attachment
                      Without the example of the GPF (so please forgive my assumptions, if
                      they are wrong)...

                      I have written two functions - safe_strlen and safe_strcpy (and a main
                      to show it working).

                      strlen is unsafe, because it just keeps on going and going until it
                      finds a 0 (think bunny with drum)

                      strncpy (I guess) is unsafe because it calls strlen (though perhaps it
                      is inline)

                      NOTE: safe_strlen is (as demonstrated) safe with any memory passed to it
                      regardless
                      NOTE: safe_strncpy adds a null terminator - this may be wrong according
                      to strncpy, I didn't bother to check (if so, sorry)

                      HTH

                      Bruce

                      Bram Moolenaar wrote:

                      >Bruce Mellows wrote:
                      >
                      >
                      >
                      >>This is the code to protect a function from a GPF.
                      >>
                      >>NOTE...
                      >>
                      >>- The critical part of the work *MUST* be done in assembler - so I
                      >>decided that it might be best if it was ALL in assembler - so it can be
                      >>in one place (the actual exception handler could have been done in less
                      >>than ten lines of C).
                      >>
                      >>- The assembler used is nasm - I could re-write it in masm if that was
                      >>preferred.
                      >>
                      >>
                      >
                      >Bummer. I do like the protection against crashes, but using assembly
                      >makes it very difficult to compile Vim on various platforms (64 bit
                      >anyone?).
                      >
                      >It appears your code also catches a crash in the called function. That
                      >was not really required. Would it be possible to avoid the assembly
                      >code when we only want to check the returned pointer? There actually is
                      >a function for this (to check the validity of a pointer), but I couldn't
                      >make it work.
                      >
                      >
                      >
                    • Bruce Mellows
                      Though I hate replying to myself... I suppose safe_strncpy should have begun with size_t length = safe_strlen(src); n = min(n,length);
                      Message 10 of 15 , Oct 8, 2002
                      • 0 Attachment
                        Though I hate replying to myself...

                        I suppose safe_strncpy should have begun with

                        size_t length = safe_strlen(src);
                        n = min(n,length);

                        Bruce Mellows wrote:

                        > Without the example of the GPF (so please forgive my assumptions, if
                        > they are wrong)...
                        >
                        > I have written two functions - safe_strlen and safe_strcpy (and a main
                        > to show it working).
                        >
                        > strlen is unsafe, because it just keeps on going and going until it
                        > finds a 0 (think bunny with drum)
                        >
                        > strncpy (I guess) is unsafe because it calls strlen (though perhaps it
                        > is inline)
                        >
                        > NOTE: safe_strlen is (as demonstrated) safe with any memory passed to
                        > it regardless
                        > NOTE: safe_strncpy adds a null terminator - this may be wrong
                        > according to strncpy, I didn't bother to check (if so, sorry)
                        >
                        > HTH
                        >
                        > Bruce
                        >
                        > Bram Moolenaar wrote:
                        >
                        >> Bruce Mellows wrote:
                        >>
                        >>
                        >>
                        >>> This is the code to protect a function from a GPF.
                        >>>
                        >>> NOTE...
                        >>>
                        >>> - The critical part of the work *MUST* be done in assembler - so I
                        >>> decided that it might be best if it was ALL in assembler - so it can
                        >>> be in one place (the actual exception handler could have been done
                        >>> in less than ten lines of C).
                        >>>
                        >>> - The assembler used is nasm - I could re-write it in masm if that
                        >>> was preferred.
                        >>>
                        >>
                        >>
                        >> Bummer. I do like the protection against crashes, but using assembly
                        >> makes it very difficult to compile Vim on various platforms (64 bit
                        >> anyone?).
                        >>
                        >> It appears your code also catches a crash in the called function. That
                        >> was not really required. Would it be possible to avoid the assembly
                        >> code when we only want to check the returned pointer? There actually is
                        >> a function for this (to check the validity of a pointer), but I couldn't
                        >> make it work.
                        >>
                        >>
                        >>
                        >------------------------------------------------------------------------
                        >
                        >#include <windows.h>
                        >#include <stdio.h>
                        >
                        >char* safe_strncpy(char* dst, const char* src, size_t n)
                        >{
                        > size_t index;
                        >
                        > for (index = 0 ; index != n && src[index] ; ++index)
                        > dst[index] = src[index];
                        >
                        > dst[++index] = 0;
                        >
                        > return dst;
                        >}
                        >
                        >size_t safe_strlen(const char* str)
                        >{
                        > SYSTEM_INFO si;
                        > MEMORY_BASIC_INFORMATION mbi;
                        >
                        > size_t length = 0;
                        >
                        > /* get page size */
                        > GetSystemInfo(&si);
                        >
                        > /* get memory information */
                        > if (VirtualQuery(str, &mbi, sizeof(mbi)) && mbi.State == MEM_COMMIT)
                        > {
                        > /* pre cast these (typing savers) */
                        > DWORD dwStr = (DWORD)str;
                        > DWORD dwBaseAddress = (DWORD)mbi.BaseAddress;
                        >
                        > /* get start address of page that str is on */
                        > DWORD strPage = dwStr - (dwStr - dwBaseAddress) % si.dwPageSize;
                        >
                        > /* get length from str to end of page */
                        > DWORD pageLength = si.dwPageSize - (dwStr - strPage);
                        >
                        > /* work out the absolute maximum length of the string
                        > * NOTE: this is not strictly true - the next block of pages
                        > * may also be accessible, but this is probably good enough
                        > */
                        > DWORD maxLength = dwBaseAddress + mbi.RegionSize - strPage - (dwStr - strPage);
                        >
                        > const char* strCurr;
                        > const char* memoryEnd = str + maxLength;
                        >
                        > for (strCurr = str ; strCurr < memoryEnd ; strCurr += pageLength, pageLength = si.dwPageSize)
                        > {
                        > size_t temp;
                        > for (temp = 0 ; temp != pageLength && strCurr[temp] ; ++temp, ++length)
                        > ;
                        > if (temp != pageLength)
                        > break;
                        > }
                        > }
                        >
                        > return length;
                        >}
                        >
                        >#define BUFFER_SIZE (3 * (1<<12))
                        >int main()
                        >{
                        > char* memory = (char*) malloc(BUFFER_SIZE);
                        >
                        > if (memory)
                        > {
                        > size_t temp;
                        >
                        > ::memset(memory, 'A', BUFFER_SIZE);
                        > printf("%d\n", safe_strlen(memory));
                        >
                        > ::strcpy(memory, "TEST TEXT");
                        > printf("%d\n", safe_strlen(memory));
                        >
                        > printf("%d\n", safe_strlen(0));
                        >
                        > free(memory);
                        > }
                        > return 0;
                        >}
                        >
                        >
                      • Bram Moolenaar
                        ... Thanks, this shows how to use VirtualQuery() to figure out if a string can be read. I wonder when this function is available. Is this a standard Win32
                        Message 11 of 15 , Oct 9, 2002
                        • 0 Attachment
                          Bruce Mellows wrote:

                          > Without the example of the GPF (so please forgive my assumptions, if
                          > they are wrong)...
                          >
                          > I have written two functions - safe_strlen and safe_strcpy (and a main
                          > to show it working).
                          >
                          > strlen is unsafe, because it just keeps on going and going until it
                          > finds a 0 (think bunny with drum)
                          >
                          > strncpy (I guess) is unsafe because it calls strlen (though perhaps it
                          > is inline)

                          Thanks, this shows how to use VirtualQuery() to figure out if a string
                          can be read. I wonder when this function is available. Is this a
                          standard Win32 function?

                          Would be good if you (or someone else) can use this to add the proper
                          check in mch_libcall() in os_mswin.c. It's around where vim_strsave()
                          us used to copy the resulting string to allocated memory.

                          --
                          hundred-and-one symptoms of being an internet addict:
                          178. You look for an icon to double-click to open your bedroom window.

                          /// Bram Moolenaar -- Bram@... -- http://www.moolenaar.net \\\
                          /// Creator of Vim - Vi IMproved -- http://www.vim.org \\\
                          \\\ Project leader for A-A-P -- http://www.a-a-p.org ///
                          \\\ Lord Of The Rings helps Uganda - http://iccf-holland.org/lotr.html ///
                        • Bruce Mellows
                          I had a quick look at putting it in and found that the call to vim_strsave uses the unsafe strlen() and a safe memmove, and vim_strnsave uses the unsafe
                          Message 12 of 15 , Oct 9, 2002
                          • 0 Attachment
                            I had a quick look at putting it in and found that the call to
                            vim_strsave uses the unsafe strlen() and a safe memmove, and
                            vim_strnsave uses the unsafe strncpy(), it looks like there needs to be
                            a vim_strnsave_no_strlen(str,n) function that uses memmove without
                            checking for length, alternately this could be done in mch_libcall() (I
                            am confident this is not acceptable).

                            I suppose that Walter would be best to shoehorn this in, as he can
                            reproduce the error, and has probably had somewhat more experience at
                            providing acceptable patches for vim (none for me).

                            Both VirtualQuery() and GetSystemInfo() are available from Windows 95
                            and Windows NT 3.1 onwards.

                            Bram Moolenaar wrote:

                            >Bruce Mellows wrote:
                            >
                            >
                            >
                            >>Without the example of the GPF (so please forgive my assumptions, if
                            >>they are wrong)...
                            >>
                            >>I have written two functions - safe_strlen and safe_strcpy (and a main
                            >>to show it working).
                            >>
                            >>strlen is unsafe, because it just keeps on going and going until it
                            >>finds a 0 (think bunny with drum)
                            >>
                            >>strncpy (I guess) is unsafe because it calls strlen (though perhaps it
                            >>is inline)
                            >>
                            >>
                            >
                            >Thanks, this shows how to use VirtualQuery() to figure out if a string
                            >can be read. I wonder when this function is available. Is this a
                            >standard Win32 function?
                            >
                            >Would be good if you (or someone else) can use this to add the proper
                            >check in mch_libcall() in os_mswin.c. It's around where vim_strsave()
                            >us used to copy the resulting string to allocated memory.
                            >
                            >
                            >
                          • Bruce Mellows
                            This is what I come up with - perhaps Walter could test it. Notice that I added the function vim_strnsave_no_strlen() which is obviously in the wrong place,
                            Message 13 of 15 , Oct 9, 2002
                            • 0 Attachment
                              This is what I come up with - perhaps Walter could test it.

                              Notice that I added the function vim_strnsave_no_strlen() which is
                              obviously in the wrong place, and probably not a good name.

                              Bram Moolenaar wrote:

                              >Bruce Mellows wrote:
                              >
                              >
                              >
                              >>Without the example of the GPF (so please forgive my assumptions, if
                              >>they are wrong)...
                              >>
                              >>I have written two functions - safe_strlen and safe_strcpy (and a main
                              >>to show it working).
                              >>
                              >>strlen is unsafe, because it just keeps on going and going until it
                              >>finds a 0 (think bunny with drum)
                              >>
                              >>strncpy (I guess) is unsafe because it calls strlen (though perhaps it
                              >>is inline)
                              >>
                              >>
                              >
                              >Thanks, this shows how to use VirtualQuery() to figure out if a string
                              >can be read. I wonder when this function is available. Is this a
                              >standard Win32 function?
                              >
                              >Would be good if you (or someone else) can use this to add the proper
                              >check in mch_libcall() in os_mswin.c. It's around where vim_strsave()
                              >us used to copy the resulting string to allocated memory.
                              >
                              >
                              >
                            • Bruce Mellows
                              This would be a better version of this function - the difference is that I use IsBadReadPtr on each page before I look for 0, rather than assuming committed
                              Message 14 of 15 , Oct 10, 2002
                              • 0 Attachment
                                This would be a better version of this function - the difference is that
                                I use IsBadReadPtr on each page before I look for 0, rather than
                                assuming committed pages are readable (which is a seriously bad assumption)

                                Perhaps Walter or Vince would like to provide me with the DLL that
                                returns an invalid string, so I could test it (and a short note or vim
                                script that hits the problem).

                                Remember that it is not possible to protect against a GPF inside the DLL
                                without setting up a structured exception handler (which I would recommend).

                                Back on the topic of catching and recovering from a GPF - perhaps we
                                could enable this in Win32, and add the code for Win64 when we know it -
                                wouldn't this be better than nothing - especially given the prevalence
                                of Win32 over Win64 at this stage.

                                size_t
                                mch_strlen(
                                char_u *str)
                                {
                                SYSTEM_INFO si;
                                MEMORY_BASIC_INFORMATION mbi;

                                size_t length = 0;

                                /* get page size */
                                GetSystemInfo(&si);

                                /* get memory information */
                                if (VirtualQuery(str, &mbi, sizeof(mbi)))
                                {
                                /* pre cast these (typing savers) */
                                DWORD dwStr = (DWORD)str;
                                DWORD dwBaseAddress = (DWORD)mbi.BaseAddress;

                                /* get start address of page that str is on */
                                DWORD strPage = dwStr - (dwStr - dwBaseAddress) % si.dwPageSize;

                                /* get length from str to end of page */
                                DWORD pageLength = si.dwPageSize - (dwStr - strPage);

                                const char* strCurr;

                                for (strCurr = str ; !IsBadReadPtr(strCurr, pageLength) ;
                                strCurr += pageLength, pageLength = si.dwPageSize)
                                {
                                size_t temp;
                                for (temp = 0 ; temp != pageLength && strCurr[temp] ;
                                ++temp, ++length)
                                ;
                                if (temp != pageLength)
                                break;
                                }
                                }

                                return length;
                                }


                                Bruce Mellows wrote:

                                > This is what I come up with - perhaps Walter could test it.
                                >
                                > Notice that I added the function vim_strnsave_no_strlen() which is
                                > obviously in the wrong place, and probably not a good name.
                                >
                                > Bram Moolenaar wrote:
                                >
                                >> Bruce Mellows wrote:
                                >>
                                >>
                                >>
                                >>> Without the example of the GPF (so please forgive my assumptions, if
                                >>> they are wrong)...
                                >>>
                                >>> I have written two functions - safe_strlen and safe_strcpy (and a
                                >>> main to show it working).
                                >>>
                                >>> strlen is unsafe, because it just keeps on going and going until it
                                >>> finds a 0 (think bunny with drum)
                                >>>
                                >>> strncpy (I guess) is unsafe because it calls strlen (though perhaps
                                >>> it is inline)
                                >>>
                                >>
                                >>
                                >> Thanks, this shows how to use VirtualQuery() to figure out if a string
                                >> can be read. I wonder when this function is available. Is this a
                                >> standard Win32 function?
                                >>
                                >> Would be good if you (or someone else) can use this to add the proper
                                >> check in mch_libcall() in os_mswin.c. It's around where vim_strsave()
                                >> us used to copy the resulting string to allocated memory.
                                >>
                                >>
                                >>
                                >------------------------------------------------------------------------
                                >
                                >Index: src/os_mswin.c
                                >===================================================================
                                >RCS file: /cvsroot/vim/vim/src/os_mswin.c,v
                                >retrieving revision 1.34
                                >diff -c -r1.34 os_mswin.c
                                >*** src/os_mswin.c 11 Mar 2002 23:22:28 -0000 1.34
                                >--- src/os_mswin.c 10 Oct 2002 00:34:45 -0000
                                >***************
                                >*** 649,654 ****
                                >--- 649,719 ----
                                > typedef int (*MYINTPROCINT)(int);
                                > #endif
                                >
                                >+ size_t
                                >+ mch_strlen(
                                >+ char_u *str)
                                >+ {
                                >+ SYSTEM_INFO si;
                                >+ MEMORY_BASIC_INFORMATION mbi;
                                >+ size_t length = 0;
                                >+
                                >+ /* get page size */
                                >+ GetSystemInfo(&si);
                                >+
                                >+ /* get memory information */
                                >+ if (VirtualQuery(str, &mbi, sizeof(mbi)) && mbi.State == MEM_COMMIT)
                                >+ {
                                >+ /* pre cast these (typing savers) */
                                >+ DWORD dwStr = (DWORD)str;
                                >+ DWORD dwBaseAddress = (DWORD)mbi.BaseAddress;
                                >+
                                >+ /* get start address of page that str is on */
                                >+ DWORD strPage = dwStr - (dwStr - dwBaseAddress) % si.dwPageSize;
                                >+
                                >+ /* get length from str to end of page */
                                >+ DWORD pageLength = si.dwPageSize - (dwStr - strPage);
                                >+
                                >+ /* work out the absolute maximum length of the string
                                >+ * NOTE: this is not strictly true - the next block of pages
                                >+ * may also be accessible, but this is probably good enough
                                >+ */
                                >+ DWORD maxLength = dwBaseAddress + mbi.RegionSize - strPage - (dwStr - strPage);
                                >+
                                >+ char_u* strCurr;
                                >+ char_u* memoryEnd = str + maxLength;
                                >+
                                >+ for (strCurr = str ; strCurr < memoryEnd ; strCurr += pageLength, pageLength = si.dwPageSize)
                                >+ {
                                >+ size_t temp;
                                >+ for (temp = 0 ; temp != pageLength && strCurr[temp] ; ++temp, ++length)
                                >+ ;
                                >+ if (temp != pageLength)
                                >+ break;
                                >+ }
                                >+ }
                                >+
                                >+ return length;
                                >+ }
                                >+
                                >+ char_u *
                                >+ vim_strnsave_no_strlen(string, len)
                                >+ char_u *string;
                                >+ int len;
                                >+ {
                                >+ char_u *p;
                                >+ int addNull = string[len]?1:0;
                                >+
                                >+ p = alloc(len+addNull);
                                >+ if (p != NULL)
                                >+ {
                                >+ mch_memmove(p, string, (size_t)len);
                                >+ if (addNull)
                                >+ p[len]=0;
                                >+ }
                                >+ return p;
                                >+ }
                                >+
                                >+
                                > int
                                > mch_libcall(
                                > char_u *libname,
                                >***************
                                >*** 663,668 ****
                                >--- 728,734 ----
                                > MYINTPROCSTR ProcAddI;
                                > char_u *retval_str = NULL;
                                > int retval_int = 0;
                                >+ size_t strLength;
                                >
                                > BOOL fRunTimeLinkSuccess = FALSE;
                                >
                                >***************
                                >*** 701,711 ****
                                > // Assume that a "1" result is an illegal pointer.
                                > if (string_result == NULL)
                                > *number_result = retval_int;
                                >! else if (retval_str != NULL
                                >! && retval_str != (char_u *)1
                                >! && retval_str != (char_u *)-1
                                >! && !IsBadStringPtr(retval_str, INT_MAX))
                                >! *string_result = vim_strsave(retval_str);
                                >
                                > // Free the DLL module.
                                > (void)FreeLibrary(hinstLib);
                                >--- 767,774 ----
                                > // Assume that a "1" result is an illegal pointer.
                                > if (string_result == NULL)
                                > *number_result = retval_int;
                                >! else if (0 != (strLength = mch_strlen(retval_str)))
                                >! *string_result = vim_strnsave_no_strlen(retval_str, strLength);
                                >
                                > // Free the DLL module.
                                > (void)FreeLibrary(hinstLib);
                                >
                                >
                              • Walter Briscoe
                                In article of Thu, 3 Oct 2002 20:06:52 in , Bram Moolenaar writes ... [snip] ... I have found no
                                Message 15 of 15 , Oct 11, 2002
                                • 0 Attachment
                                  In article <200210031806.g93I6qu02401@...> of Thu, 3 Oct 2002
                                  20:06:52 in , Bram Moolenaar <Bram@...> writes
                                  >
                                  >Walter Briscoe wrote:
                                  >
                                  [snip]
                                  >> I shall look at:
                                  >> > 9 When using libcall() for a function that returns an invalid
                                  >> >pointer, Vim
                                  >> > crashes. Check for a bad pointer with isBadReadPtr() doesn't appear to
                                  >> > work well.
                                  >> Steve Oualline's book does not mention libcall. I see it is mentioned in
                                  >> version5.txt as a contribution from Negri. Perhaps Vince can get me up
                                  >> to speed with a demonstration of the feature. It must be useful as it
                                  >> was originally implemented only in Win32 and is now also done in UNIX.
                                  >
                                  >It would be good if you can fix this. I did an attempt once, but
                                  >couldn't find a way to avoid a crash. Best is if any use of libcall()
                                  >detects that a pointer is not valid and gives an error message instead
                                  >of crashing.
                                  >

                                  I have found no crash in the mch_libcall() in os_mswin.c. I tested in
                                  W2K, WME, and W95 with the following source which is an adaptation of
                                  something provided by Vince Negri:

                                  C:\wfb\vim\bld\vim61\src> type dummydll.c
                                  /*
                                  * DUMMYDLL.C
                                  *
                                  * Dummy to exercise Vim libcall function
                                  *
                                  * VC make: cl /LD DUMMYDLL.C /link /nodefaultlib libcmt.lib kernel32.lib
                                  *
                                  * When Who What
                                  * 1999-03-12 V.Negri aslutil.c written
                                  * 2002-10-11 W.Briscoe Dummy DLL written as aslutil.dll unloadable on WME
                                  */

                                  #pragma warning(disable: 4100 4115 4201 4214 4514)
                                  #include <windows.h>
                                  #pragma warning(default: 4100 4115 4201 4214)

                                  __declspec(dllexport) long get_long(const char *strLocalFullName)
                                  {
                                  return atol(strLocalFullName);
                                  }

                                  __declspec(dllexport) LPTSTR get_string(const char *strLocalFullName)
                                  {
                                  return (TCHAR*)strLocalFullName;
                                  }


                                  C:\wfb\vim\bld\vim61\src>


                                  I was interested in Bruce's assertions about GPF handling.
                                  I found the following worked as I wanted:

                                  C:\wfb\vim\bld\vim61\src> type sigsegv.c
                                  /*
                                  * sigsegv.c
                                  *
                                  * Simple look at SIGSEGV
                                  *
                                  * When Who What
                                  * 2002-10-11 W.Briscoe Original
                                  */
                                  #include <setjmp.h>
                                  #include <signal.h>
                                  #include <stdio.h>

                                  jmp_buf get_back;

                                  void handler(int sig) {
                                  printf("handler(%d)\n", sig);
                                  longjmp(get_back, 1);
                                  }

                                  int main(void) {
                                  (void)signal(SIGSEGV, handler);

                                  if (setjmp(get_back) == 0)
                                  *(char*)0 = 42;
                                  puts("Done");
                                  return 0;
                                  }

                                  C:\wfb\vim\bld\vim61\src>

                                  On the other hand, there was a GPF message box rather than a call of my
                                  handler when I used the vim command
                                  let result = libcall('dummydll', 'get_long', 42)

                                  For that, I used:

                                  C:\wfb\vim\bld\vim61\src> type 1dummydll.c
                                  /*
                                  * DUMMYDLL.C
                                  *
                                  * Dummy to exercise Vim libcall function
                                  *
                                  * VC make: cl /LD DUMMYDLL.C /link /nodefaultlib libcmt.lib kernel32.lib
                                  *
                                  * When Who What
                                  * 1999-03-12 V.Negri aslutil.c written
                                  * 2002-10-11 W.Briscoe Dummy DLL written as aslutil.dll unloadable on WME
                                  * 2002-10-11 W.Briscoe Added SIGSEGV handler to show it can be done.
                                  */

                                  #include <setjmp.h>
                                  #include <signal.h>
                                  #include <stdio.h>

                                  #pragma warning(disable: 4100 4115 4201 4214 4514)
                                  #include <windows.h>
                                  #pragma warning(default: 4100 4115 4201 4214)

                                  static jmp_buf get_back;

                                  void handler(int sig) {
                                  printf("handler(%d)\n", sig);
                                  Sleep(2000); // 2 second wait so message can be seen
                                  longjmp(get_back, 1);
                                  }

                                  __declspec(dllexport) long get_long(const char *strLocalFullName)
                                  {
                                  void (*old)(int) = signal(SIGSEGV, handler);
                                  long result = 0;

                                  if (setjmp(get_back) == 0)
                                  result = atol(strLocalFullName);

                                  (void)signal(SIGSEGV, old);

                                  return result;
                                  }

                                  __declspec(dllexport) LPTSTR get_string(const char *strLocalFullName)
                                  {
                                  return (TCHAR*)strLocalFullName;
                                  }


                                  C:\wfb\vim\bld\vim61\src>

                                  Should mch_libcall() guard against numbers being passed where strings
                                  are needed? I think not - function parameter validation is a higher
                                  level issue. I found mch_libcall() coding verbose. I am more comfortable
                                  with the following. YMMV :) mch_libcall() compiles at -W4 rather than -
                                  W3 and PC-Lint is silent about it except that I have not used const
                                  qualifiers. It continues to regard an unreadable output string
                                  successful and (implicitly) translates them to "". Non-NULL unreadable
                                  strings are reported. (I overloaded the text of E364. Alternatively, I
                                  found E460 available.) I tested in W2K, WME, and W95 with
                                  :let result = libcall('dummydll', 'get_string', x) for x in -1, 0, 1,
                                  42. I can't break it in mch_libcall. I will be DELIGHTED to deal with a
                                  scenario where someone else can.

                                  *** vim61/src/0os_mswin.c Mon Mar 11 20:46:50 2002
                                  --- vim61/src/os_mswin.c Fri Oct 11 11:27:00 2002
                                  ***************
                                  *** 633,654 ****

                                  #ifdef FEAT_EVAL
                                  /*
                                  ! * Call a DLL routine which takes either a string or int param
                                  ! * and returns an allocated string.
                                  * Return OK if it worked, FAIL if not.
                                  */
                                  - #ifdef WIN3264
                                  - typedef LPTSTR (*MYSTRPROCSTR)(LPTSTR);
                                  - typedef LPTSTR (*MYINTPROCSTR)(int);
                                  - typedef int (*MYSTRPROCINT)(LPTSTR);
                                  - typedef int (*MYINTPROCINT)(int);
                                  - #else
                                  - typedef LPSTR (*MYSTRPROCSTR)(LPSTR);
                                  - typedef LPSTR (*MYINTPROCSTR)(int);
                                  - typedef int (*MYSTRPROCINT)(LPSTR);
                                  - typedef int (*MYINTPROCINT)(int);
                                  - #endif
                                  -
                                  int
                                  mch_libcall(
                                  char_u *libname,
                                  --- 633,642 ----

                                  #ifdef FEAT_EVAL
                                  /*
                                  ! * Call a DLL routine which takes either a string or int param and
                                  ! * returns either an allocated string or an int. These are not set on failure.
                                  * Return OK if it worked, FAIL if not.
                                  */
                                  int
                                  mch_libcall(
                                  char_u *libname,
                                  ***************
                                  *** 658,722 ****
                                  char_u **string_result,/* NULL when using number_result */
                                  int *number_result)
                                  {
                                  ! HINSTANCE hinstLib;
                                  ! MYSTRPROCSTR ProcAdd;
                                  ! MYINTPROCSTR ProcAddI;
                                  ! char_u *retval_str = NULL;
                                  ! int retval_int = 0;
                                  !
                                  ! BOOL fRunTimeLinkSuccess = FALSE;

                                  ! // Get a handle to the DLL module.
                                  ! hinstLib = LoadLibrary(libname);
                                  !
                                  ! // If the handle is valid, try to get the function address.
                                  ! if (hinstLib != NULL)
                                  {
                                  ! if (argstring != NULL)
                                  ! {
                                  ! /* Call with string argument */
                                  ! ProcAdd = (MYSTRPROCSTR) GetProcAddress(hinstLib, funcname);
                                  ! if ((fRunTimeLinkSuccess = (ProcAdd != NULL)) != 0)
                                  ! {
                                  ! if (string_result == NULL)
                                  ! retval_int = ((MYSTRPROCINT)ProcAdd)(argstring);
                                  ! else
                                  ! retval_str = (ProcAdd)(argstring);
                                  ! }
                                  ! }
                                  ! else
                                  ! {
                                  ! /* Call with number argument */
                                  ! ProcAddI = (MYINTPROCSTR) GetProcAddress(hinstLib, funcname);
                                  ! if ((fRunTimeLinkSuccess = (ProcAddI != NULL)) != 0)
                                  ! {
                                  ! if (string_result == NULL)
                                  ! retval_int = ((MYINTPROCINT)ProcAddI)(argint);
                                  ! else
                                  ! retval_str = (ProcAddI)(argint);
                                  ! }
                                  ! }
                                  !
                                  ! // Save the string before we free the library.
                                  ! // Assume that a "1" result is an illegal pointer.
                                  ! if (string_result == NULL)
                                  ! *number_result = retval_int;
                                  ! else if (retval_str != NULL
                                  ! && retval_str != (char_u *)1
                                  ! && retval_str != (char_u *)-1
                                  ! && !IsBadStringPtr(retval_str, INT_MAX))
                                  ! *string_result = vim_strsave(retval_str);

                                  ! // Free the DLL module.
                                  ! (void)FreeLibrary(hinstLib);
                                  }

                                  ! if (!fRunTimeLinkSuccess)
                                  {
                                  ! EMSG2(_("E364: Library call failed for \"%s()\""), funcname);
                                  ! return FAIL;
                                  }

                                  return OK;
                                  }
                                  #endif
                                  --- 646,684 ----
                                  char_u **string_result,/* NULL when using number_result */
                                  int *number_result)
                                  {
                                  ! HINSTANCE hinstLib;
                                  ! FARPROC ProcAdd;
                                  ! char etext[1024];
                                  ! void *retval_str;

                                  ! if ((hinstLib = LoadLibrary((void*)libname)) == NULL
                                  ! || (ProcAdd = GetProcAddress(hinstLib, (void*)funcname)) == NULL)
                                  {
                                  ! if (hinstLib != NULL)
                                  ! (void)FreeLibrary(hinstLib);

                                  ! EMSG2(_("E364: Library call failed for \"%s()\""), funcname);
                                  ! return FAIL;
                                  }

                                  ! if (string_result == NULL)
                                  ! // Call to set number result
                                  ! *number_result = (argstring != NULL)
                                  ! ? ((int (*)(void*))ProcAdd)(argstring)
                                  ! : ((int (*)(int ))ProcAdd)(argint);
                                  ! // Call to set string result
                                  ! else if (!IsBadStringPtr(retval_str = ((argstring != NULL)
                                  ! ? ((void*(*)(void*))ProcAdd)(argstring)
                                  ! : ((void*(*)(int ))ProcAdd)(argint)), INT_MAX))
                                  ! // If plausible, save the string before we free the DLL module.
                                  ! *string_result = vim_strsave(retval_str);
                                  ! else if (retval_str != NULL)
                                  {
                                  ! sprintf(etext, "E364: Bad string at %p from \"%%s()\"", retval_str);
                                  ! EMSG2(etext, funcname);
                                  }

                                  + (void)FreeLibrary(hinstLib);
                                  return OK;
                                  }
                                  #endif

                                  --
                                  Walter Briscoe
                                Your message has been successfully submitted and would be delivered to recipients shortly.