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

Re: What a to-do!

Expand Messages
  • Walter Briscoe
    In article of Thu, 3 Oct 2002 20:06:52 in , Bram Moolenaar writes ... [snip] ... I have found no
    Message 1 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.