Skip to content

Commit e84428c

Browse files
Fixes: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc #1015 (#1018)
Signed-off-by: Balram Choudhary <bchoudhary@rocketsoftware.com>
1 parent 0cfe21b commit e84428c

1 file changed

Lines changed: 61 additions & 36 deletions

File tree

ibm_db.c

Lines changed: 61 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -700,23 +700,19 @@ static void _python_ibm_db_check_sql_errors(SQLHANDLE handle, SQLSMALLINT hType,
700700
snprintf(messageStr, sizeof(messageStr), "handle=%p, hType=%d, rc=%d, cpy_to_global=%d, API=%d, recno=%d",
701701
handle, hType, rc, cpy_to_global, API, recno);
702702
LogMsg(DEBUG, messageStr);
703-
704-
memset(errMsg, '\0', DB2_MAX_ERR_MSG_LEN);
705-
memset(msg, '\0', SQL_MAX_MESSAGE_LENGTH + 1);
706703
rc1 = SQLGetDiagRec(hType, handle, recno, sqlstate, &sqlcode, msg,
707704
SQL_MAX_MESSAGE_LENGTH + 1, &length);
708-
snprintf(messageStr, sizeof(messageStr), "SQLGetDiagRec returned rc1=%d, sqlstate=%s, sqlcode=%d, msg=%s, length=%d",
709-
rc1, sqlstate, sqlcode, msg, length);
705+
snprintf(messageStr, sizeof(messageStr), "SQLGetDiagRec returned rc1=%d, sqlstate=%s, sqlcode=%d, length=%d",
706+
rc1, sqlstate, sqlcode, length);
710707
sprintf((char *)errcode, "SQLCODE=%d", (int)sqlcode);
711708
LogMsg(DEBUG, messageStr);
712-
713709
if (rc1 == SQL_SUCCESS)
714710
{
715711
while ((p = strchr((char *)msg, '\n')))
716712
{
717713
*p = '\0';
718714
}
719-
sprintf((char *)errMsg, "%s SQLCODE=%d", (char *)msg, (int)sqlcode);
715+
snprintf((char *)errMsg, DB2_MAX_ERR_MSG_LEN, "%s SQLCODE=%d", (char *)msg, (int)sqlcode);
720716
#ifdef _WIN32
721717
for (i = 0; i < strlen(errMsg); i++)
722718
{
@@ -727,7 +723,8 @@ static void _python_ibm_db_check_sql_errors(SQLHANDLE handle, SQLSMALLINT hType,
727723
}
728724
#endif
729725

730-
LogMsg(ERROR, errMsg);
726+
snprintf(messageStr, sizeof(messageStr), "Final error message (UTF-8): %s", errMsg);
727+
LogMsg(ERROR, messageStr);
731728
if (cpy_to_global != 0 && rc != 1)
732729
{
733730
PyErr_SetString(PyExc_Exception, (char *)errMsg);
@@ -747,25 +744,30 @@ static void _python_ibm_db_check_sql_errors(SQLHANDLE handle, SQLSMALLINT hType,
747744
"Copying to global: SQL_HANDLE_DBC, sqlstate=%s, errMsg=%s",
748745
sqlstate, errMsg);
749746
LogMsg(DEBUG, messageStr);
750-
strncpy(IBM_DB_G(__python_conn_err_state),
751-
(char *)sqlstate, SQL_SQLSTATE_SIZE + 1);
752-
strncpy(IBM_DB_G(__python_conn_err_msg),
753-
(char *)errMsg, DB2_MAX_ERR_MSG_LEN);
754-
strncpy(IBM_DB_G(__python_err_code),
755-
(char *)errcode, SQL_SQLCODE_SIZE);
747+
strncpy(IBM_DB_G(__python_conn_err_state), (char *)sqlstate, SQL_SQLSTATE_SIZE);
748+
IBM_DB_G(__python_conn_err_state)[SQL_SQLSTATE_SIZE] = '\0';
749+
750+
strncpy(IBM_DB_G(__python_conn_err_msg), (char *)errMsg, DB2_MAX_ERR_MSG_LEN - 1);
751+
IBM_DB_G(__python_conn_err_msg)[DB2_MAX_ERR_MSG_LEN - 1] = '\0';
752+
753+
strncpy(IBM_DB_G(__python_err_code), (char *)errcode, SQL_SQLCODE_SIZE - 1);
754+
IBM_DB_G(__python_err_code)[SQL_SQLCODE_SIZE - 1] = '\0';
755+
756756
break;
757757

758758
case SQL_HANDLE_STMT:
759759
snprintf(messageStr, sizeof(messageStr),
760760
"Copying to global: SQL_HANDLE_STMT, sqlstate=%s, errMsg=%s",
761761
sqlstate, errMsg);
762762
LogMsg(DEBUG, messageStr);
763-
strncpy(IBM_DB_G(__python_stmt_err_state),
764-
(char *)sqlstate, SQL_SQLSTATE_SIZE + 1);
765-
strncpy(IBM_DB_G(__python_stmt_err_msg),
766-
(char *)errMsg, DB2_MAX_ERR_MSG_LEN);
767-
strncpy(IBM_DB_G(__python_err_code),
768-
(char *)errcode, SQL_SQLCODE_SIZE);
763+
strncpy(IBM_DB_G(__python_stmt_err_state), (char *)sqlstate, SQL_SQLSTATE_SIZE);
764+
IBM_DB_G(__python_stmt_err_state)[SQL_SQLSTATE_SIZE] = '\0';
765+
766+
strncpy(IBM_DB_G(__python_stmt_err_msg), (char *)errMsg, DB2_MAX_ERR_MSG_LEN - 1);
767+
IBM_DB_G(__python_stmt_err_msg)[DB2_MAX_ERR_MSG_LEN - 1] = '\0';
768+
769+
strncpy(IBM_DB_G(__python_err_code), (char *)errcode, SQL_SQLCODE_SIZE - 1);
770+
IBM_DB_G(__python_err_code)[SQL_SQLCODE_SIZE - 1] = '\0';
769771

770772
break;
771773
}
@@ -779,15 +781,17 @@ static void _python_ibm_db_check_sql_errors(SQLHANDLE handle, SQLSMALLINT hType,
779781
{
780782
snprintf(messageStr, sizeof(messageStr), "Returning SQLSTATE for DB2_ERR: %s", sqlstate);
781783
LogMsg(DEBUG, messageStr);
782-
strncpy(ret_str, (char *)sqlstate, SQL_SQLSTATE_SIZE + 1);
784+
strncpy(ret_str, (char *)sqlstate, SQL_SQLSTATE_SIZE);
785+
ret_str[SQL_SQLSTATE_SIZE] = '\0';
783786
}
784787
return;
785788
case DB2_ERRMSG:
786789
if (ret_str != NULL)
787790
{
788791
snprintf(messageStr, sizeof(messageStr), "Returning error message for DB2_ERRMSG: %s", errMsg);
789792
LogMsg(DEBUG, messageStr);
790-
strncpy(ret_str, (char *)errMsg, DB2_MAX_ERR_MSG_LEN);
793+
strncpy(ret_str, (char *)errMsg, DB2_MAX_ERR_MSG_LEN - 1);
794+
ret_str[DB2_MAX_ERR_MSG_LEN - 1] = '\0';
791795
}
792796
return;
793797
default:
@@ -806,21 +810,23 @@ static void _python_ibm_db_check_sql_errors(SQLHANDLE handle, SQLSMALLINT hType,
806810
"Copying warning to global: SQL_HANDLE_DBC, sqlstate=%s, errMsg=%s",
807811
sqlstate, errMsg);
808812
LogMsg(DEBUG, messageStr);
809-
strncpy(IBM_DB_G(__python_conn_warn_state),
810-
(char *)sqlstate, SQL_SQLSTATE_SIZE + 1);
811-
strncpy(IBM_DB_G(__python_conn_warn_msg),
812-
(char *)errMsg, DB2_MAX_ERR_MSG_LEN);
813+
strncpy(IBM_DB_G(__python_conn_warn_state), (char *)sqlstate, SQL_SQLSTATE_SIZE);
814+
IBM_DB_G(__python_conn_warn_state)[SQL_SQLSTATE_SIZE] = '\0';
815+
816+
strncpy(IBM_DB_G(__python_conn_warn_msg), (char *)errMsg, DB2_MAX_ERR_MSG_LEN - 1);
817+
IBM_DB_G(__python_conn_warn_msg)[DB2_MAX_ERR_MSG_LEN - 1] = '\0';
813818
break;
814819

815820
case SQL_HANDLE_STMT:
816821
snprintf(messageStr, sizeof(messageStr),
817822
"Copying warning to global: SQL_HANDLE_STMT, sqlstate=%s, errMsg=%s",
818823
sqlstate, errMsg);
819824
LogMsg(DEBUG, messageStr);
820-
strncpy(IBM_DB_G(__python_stmt_warn_state),
821-
(char *)sqlstate, SQL_SQLSTATE_SIZE + 1);
822-
strncpy(IBM_DB_G(__python_stmt_warn_msg),
823-
(char *)errMsg, DB2_MAX_ERR_MSG_LEN);
825+
strncpy(IBM_DB_G(__python_stmt_warn_state), (char *)sqlstate, SQL_SQLSTATE_SIZE);
826+
IBM_DB_G(__python_stmt_warn_state)[SQL_SQLSTATE_SIZE] = '\0';
827+
828+
strncpy(IBM_DB_G(__python_stmt_warn_msg), (char *)errMsg, DB2_MAX_ERR_MSG_LEN - 1);
829+
IBM_DB_G(__python_stmt_warn_msg)[DB2_MAX_ERR_MSG_LEN - 1] = '\0';
824830
break;
825831
}
826832
}
@@ -830,7 +836,8 @@ static void _python_ibm_db_check_sql_errors(SQLHANDLE handle, SQLSMALLINT hType,
830836
{
831837
snprintf(messageStr, sizeof(messageStr), "Returning warning message for DB2_WARNMSG: %s", errMsg);
832838
LogMsg(DEBUG, messageStr);
833-
strncpy(ret_str, (char *)errMsg, DB2_MAX_ERR_MSG_LEN);
839+
strncpy(ret_str, (char *)errMsg, DB2_MAX_ERR_MSG_LEN - 1);
840+
ret_str[DB2_MAX_ERR_MSG_LEN - 1] = '\0';
834841
}
835842
return;
836843
default:
@@ -9928,11 +9935,20 @@ static PyObject *ibm_db_conn_errormsg(PyObject *self, PyObject *args)
99289935
}
99299936
else
99309937
{
9931-
PyObject *defaultErrorMsg = StringOBJ_FromASCII(IBM_DB_G(__python_conn_err_msg));
9932-
snprintf(messageStr, sizeof(messageStr), "No connection object provided. Returning default error message: %s", PyUnicode_AsUTF8(defaultErrorMsg));
9938+
PyObject *defaultErrorMsg = PyUnicode_DecodeUTF8(
9939+
(const char *)IBM_DB_G(__python_conn_err_msg),
9940+
strlen((const char *)IBM_DB_G(__python_conn_err_msg)),
9941+
"replace"
9942+
);
9943+
snprintf(messageStr, sizeof(messageStr), "No statement object provided. Returning default error message: %s", PyUnicode_AsUTF8(defaultErrorMsg));
9944+
Py_DECREF(defaultErrorMsg);
99339945
LogMsg(INFO, messageStr);
99349946
LogMsg(INFO, "exit conn_errormsg()");
9935-
return StringOBJ_FromASCII(IBM_DB_G(__python_conn_err_msg));
9947+
return PyUnicode_DecodeUTF8(
9948+
(const char *)IBM_DB_G(__python_conn_err_msg),
9949+
strlen((const char *)IBM_DB_G(__python_conn_err_msg)),
9950+
"replace"
9951+
);
99369952
}
99379953
}
99389954
/*!# ibm_db_conn_warn
@@ -10226,11 +10242,20 @@ static PyObject *ibm_db_stmt_errormsg(PyObject *self, PyObject *args)
1022610242
}
1022710243
else
1022810244
{
10229-
PyObject *defaultErrorMsg = StringOBJ_FromASCII(IBM_DB_G(__python_stmt_err_msg));
10245+
PyObject *defaultErrorMsg = PyUnicode_DecodeUTF8(
10246+
(const char *)IBM_DB_G(__python_stmt_err_msg),
10247+
strlen((const char *)IBM_DB_G(__python_stmt_err_msg)),
10248+
"replace"
10249+
);
1023010250
snprintf(messageStr, sizeof(messageStr), "No statement object provided. Returning default error message: %s", PyUnicode_AsUTF8(defaultErrorMsg));
10251+
Py_DECREF(defaultErrorMsg);
1023110252
LogMsg(INFO, messageStr);
1023210253
LogMsg(INFO, "exit stmt_errormsg()");
10233-
return StringOBJ_FromStr(IBM_DB_G(__python_stmt_err_msg));
10254+
return PyUnicode_DecodeUTF8(
10255+
(const char *)IBM_DB_G(__python_stmt_err_msg),
10256+
strlen((const char *)IBM_DB_G(__python_stmt_err_msg)),
10257+
"replace"
10258+
);
1023410259
}
1023510260
}
1023610261

0 commit comments

Comments
 (0)