Handle StrLen_or_IndPtr argument of SQLBindParameter() properly when StrLen_or_IndPtr...
authorHiroshi Inoue <h-inoue@dream.email.ne.jp>
Fri, 21 Jul 2017 09:24:03 +0000 (18:24 +0900)
committerHiroshi Inoue <h-inoue@dream.email.ne.jp>
Mon, 24 Jul 2017 22:56:42 +0000 (07:56 +0900)
This change fixes MSACCESS errors reported by Christian Ullrich and Robert Ball.

convert.c
unicode_support.h
win_unicode.c

index b25b49765561afbd532fb7a1198c44b1a753a0f9..8f94557c7de15ce9bca630926f20658fece47a9d 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -4301,7 +4301,7 @@ inolog("ipara=%p paramType=%d %d proc_return=%d\n", ipara, ipara ? ipara->paramT
                if (!same_encoding || wcs_debug)
                {
                    mylog("%s:locale param convert\n", __FUNCTION__);
-                   if ((used = bindpara_msg_to_utf8(buffer, &allocbuf)) < 0)
+                   if ((used = bindpara_msg_to_utf8(buffer, &allocbuf, used)) < 0)
                    {
                        qb->errormsg = "Could not convert from the current locale to wide characters";
                        qb->errornumber = STMT_EXEC_ERROR;
@@ -4315,7 +4315,7 @@ inolog("ipara=%p paramType=%d %d proc_return=%d\n", ipara, ipara ? ipara->paramT
                if (!is_utf8 || (same_encoding && wcs_debug))
                {
                    mylog("%s:hybrid param convert\n", __FUNCTION__);
-                   if ((used = bindpara_wchar_to_msg((SQLWCHAR *) buffer, &allocbuf)) < 0)
+                   if ((used = bindpara_wchar_to_msg((SQLWCHAR *) buffer, &allocbuf, used)) < 0)
                    {
                        qb->errormsg = "Could not convert from wide characters to the current locale";
                        qb->errornumber = STMT_EXEC_ERROR;
index 1e6fa7cf6758b56672ae7aba990a53793fe31fb6..decf96715d8d216fbb1ac054c9e95a87bf9e3ddd 100644 (file)
@@ -28,8 +28,8 @@ SQLLEN bindcol_hybrid_estimate(const char *ldt, BOOL lf_conv, char **wcsbuf);
 SQLLEN bindcol_hybrid_exec(SQLWCHAR *utf16, const char *ldt, size_t n, BOOL lf_conv, char **wcsbuf);
 SQLLEN bindcol_localize_estimate(const char *utf8dt, BOOL lf_conv, char **wcsbuf);
 SQLLEN bindcol_localize_exec(char *ldt, size_t n, BOOL lf_conv, char **wcsbuf);
-SQLLEN bindpara_msg_to_utf8(const char *ldt, char **wcsbuf);
-SQLLEN bindpara_wchar_to_msg(const SQLWCHAR *utf16, char **wcsbuf);
+SQLLEN bindpara_msg_to_utf8(const char *ldt, char **wcsbuf, SQLLEN used);
+SQLLEN bindpara_wchar_to_msg(const SQLWCHAR *utf16, char **wcsbuf, SQLLEN used);
 
 SQLLEN locale_to_sqlwchar(SQLWCHAR *utf16, const char *ldt, size_t n, BOOL lf_conv);
 SQLLEN utf8_to_locale(char *ldt, const char * utf8dt, size_t n, BOOL lf_conv);
index 8e5bc294afff6a7cdaa3a1848e1511dbe76a720d..44fb0630e2369b9112f41c70158199a576195f46 100644 (file)
@@ -980,11 +980,35 @@ mylog(" %s:c8dt=%p size=%lu\n", __FUNCTION__, c8dt, n);
 // SQLBindParameter    SQL_C_CHAR to UTF-8 case
 //     the current locale => UTF-8
 //
-SQLLEN bindpara_msg_to_utf8(const char *ldt, char **wcsbuf)
+SQLLEN bindpara_msg_to_utf8(const char *ldt, char **wcsbuf, SQLLEN used)
 {
    SQLLEN  l = (-2);
-   char    *utf8 = NULL;
-   int     count = strlen(ldt);
+   char    *utf8 = NULL, *ldt_nts, *alloc_nts = NULL, ntsbuf[128];
+   int     count;
+
+   if (SQL_NTS == used)
+   {
+       count = strlen(ldt);
+       ldt_nts = (char *) ldt;
+   }
+   else if (used < 0)
+   {
+       return -1;
+   }
+   else
+   {
+       count = used;
+       if (used < sizeof(ntsbuf))
+           ldt_nts = ntsbuf;
+       else
+       {
+           if (NULL == (alloc_nts = malloc(used + 1)))
+               return l;
+           ldt_nts = alloc_nts;
+       }
+       memcpy(ldt_nts, ldt, used);
+       ldt_nts[used] = '\0';
+   }
  
    get_convtype();
    mylog(" %s\n", __FUNCTION__);
@@ -993,7 +1017,7 @@ SQLLEN bindpara_msg_to_utf8(const char *ldt, char **wcsbuf)
    {
        wchar_t *wcsdt = (wchar_t *) malloc((count + 1) * sizeof(wchar_t));
 
-       if ((l = msgtowstr(ldt, (wchar_t *) wcsdt, count + 1)) >= 0)
+       if ((l = msgtowstr(ldt_nts, (wchar_t *) wcsdt, count + 1)) >= 0)
            utf8 = wcs_to_utf8(wcsdt, -1, &l, FALSE);
        free(wcsdt);
    }
@@ -1003,7 +1027,7 @@ SQLLEN bindpara_msg_to_utf8(const char *ldt, char **wcsbuf)
    {
        SQLWCHAR    *utf16 = (SQLWCHAR *) malloc((count + 1) * sizeof(SQLWCHAR));
 
-       if ((l = mbstoc16_lf((char16_t *) utf16, ldt, count + 1, FALSE)) >= 0)
+       if ((l = mbstoc16_lf((char16_t *) utf16, ldt_nts, count + 1, FALSE)) >= 0)
            utf8 = ucs2_to_utf8(utf16, -1, &l, FALSE);
        free(utf16);
    }
@@ -1013,6 +1037,8 @@ SQLLEN bindpara_msg_to_utf8(const char *ldt, char **wcsbuf)
    else
        *wcsbuf = (char *) utf8;
 
+   if (NULL != alloc_nts)
+       free(alloc_nts);
    return l;
 }
 
@@ -1021,11 +1047,34 @@ SQLLEN bindpara_msg_to_utf8(const char *ldt, char **wcsbuf)
 // SQLBindParameter    hybrid case
 //     SQLWCHAR(UTF-16) => the current locale
 //
-SQLLEN bindpara_wchar_to_msg(const SQLWCHAR *utf16, char **wcsbuf)
+SQLLEN bindpara_wchar_to_msg(const SQLWCHAR *utf16, char **wcsbuf, SQLLEN used)
 {
    SQLLEN  l = (-2);
    char            *ldt = NULL;
-   int     count = ucs2strlen(utf16);
+   SQLWCHAR    *utf16_nts, *alloc_nts = NULL, ntsbuf[128];
+   int     count;
+
+   if (SQL_NTS == used)
+   {
+       count = ucs2strlen(utf16);
+       utf16_nts = (SQLWCHAR *) utf16;
+   }
+   else if (used < 0)
+       return -1;
+   else
+   {
+       count = used / WCLEN;
+       if (used + WCLEN <= sizeof(ntsbuf))
+           utf16_nts = ntsbuf;
+       else
+       {
+           if (NULL == (alloc_nts = (SQLWCHAR *) malloc(used + WCLEN)))
+               return l;
+           utf16_nts = alloc_nts;
+       }
+       memcpy(utf16_nts, utf16, used);
+       utf16_nts[count] = 0;
+   }
 
    get_convtype();
 mylog(" %s\n", __FUNCTION__);
@@ -1035,13 +1084,13 @@ mylog(" %s\n", __FUNCTION__);
        if (sizeof(SQLWCHAR) == sizeof(wchar_t))
        {
            ldt = (char *) malloc(2 * count + 1);
-           l = wstrtomsg((wchar_t *) utf16, ldt, 2 * count + 1);
+           l = wstrtomsg((wchar_t *) utf16_nts, ldt, 2 * count + 1);
        }
        else
        {
            unsigned int    *utf32 = (unsigned int *) malloc((count + 1) * sizeof(unsigned int));
 
-           l = ucs2_to_ucs4(utf16, -1, utf32, count + 1);
+           l = ucs2_to_ucs4(utf16_nts, -1, utf32, count + 1);
            if ((l = wstrtomsg((wchar_t *)utf32, NULL, 0)) >= 0)
            {
                ldt = (char *) malloc(l + 1);
@@ -1055,7 +1104,7 @@ mylog(" %s\n", __FUNCTION__);
    if (use_c16)
    {
        ldt = (char *) malloc(4 * count + 1);
-       l = c16tombs(ldt, (const char16_t *) utf16, 4 * count + 1);
+       l = c16tombs(ldt, (const char16_t *) utf16_nts, 4 * count + 1);
    }
 #endif /* __CHAR16_UTF_16__ */
    if (l < 0 && NULL != ldt)
@@ -1063,6 +1112,8 @@ mylog(" %s\n", __FUNCTION__);
    else
        *wcsbuf = ldt;
 
+   if (NULL != alloc_nts)
+       free(alloc_nts);
    return l;
 }