From 6e4a70ff435fce4c269113ca92f8d9fb3c66001e Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Thu, 23 Nov 2017 17:46:25 +0800 Subject: [PATCH 1/2] Add one char to MsiSummaryInfoGetProperty() output Based on the patch in bpo-1104 by Anthony Tuininga (atuining) and Mark Mc Mahon (markm). Unfortunately Microsoft has deemed it necessary to return the size of the string without the null termination character but insists upon the size including it when passing it in. Arggh! -- Anthony, on the fix --- Lib/test/test_msilib.py | 26 ++++++++++++++++++- .../2017-11-24-12-53-54.bpo-1104.1CWSZp.rst | 2 ++ PC/_msi.c | 3 ++- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2017-11-24-12-53-54.bpo-1104.1CWSZp.rst diff --git a/Lib/test/test_msilib.py b/Lib/test/test_msilib.py index 65ff3869c33cbe..6a1e26931ade99 100644 --- a/Lib/test/test_msilib.py +++ b/Lib/test/test_msilib.py @@ -1,4 +1,5 @@ """ Test suite for the code in msilib """ +import os import unittest from test.support import TESTFN, import_module, unlink msilib = import_module('msilib') @@ -41,6 +42,29 @@ def test_view_fetch_returns_none(self): ) self.addCleanup(unlink, db_path) + def test_summaryinfo_getproperty_issue1104(self): + db, db_path = init_database() + try: + sum_info = db.GetSummaryInformation(99) + title = sum_info.GetProperty(msilib.PID_TITLE) + self.assertEqual(title, b"Installation Database") + + sum_info.SetProperty(msilib.PID_TITLE, "a" * 999) + title = sum_info.GetProperty(msilib.PID_TITLE) + self.assertEqual(title, b"a" * 999) + + sum_info.SetProperty(msilib.PID_TITLE, "a" * 1000) + title = sum_info.GetProperty(msilib.PID_TITLE) + self.assertEqual(title, b"a" * 1000) + + sum_info.SetProperty(msilib.PID_TITLE, "a" * 1001) + title = sum_info.GetProperty(msilib.PID_TITLE) + self.assertEqual(title, b"a" * 1001) + finally: + db = None + sum_info = None + os.unlink(db_path) + class Test_make_id(unittest.TestCase): #http://msdn.microsoft.com/en-us/library/aa369212(v=vs.85).aspx @@ -73,7 +97,7 @@ def test_invalid_first_char(self): def test_invalid_any_char(self): self.assertEqual( msilib.make_id(".s\x82ort"), "_.s_ort") - self.assertEqual ( + self.assertEqual( msilib.make_id(".s\x82o?*+rt"), "_.s_o___rt") diff --git a/Misc/NEWS.d/next/Windows/2017-11-24-12-53-54.bpo-1104.1CWSZp.rst b/Misc/NEWS.d/next/Windows/2017-11-24-12-53-54.bpo-1104.1CWSZp.rst new file mode 100644 index 00000000000000..a4043496bc2463 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2017-11-24-12-53-54.bpo-1104.1CWSZp.rst @@ -0,0 +1,2 @@ +Correctly handle string length in ``msilib.SummaryInfo.GetProperty()`` to +prevent it from truncating the last character. diff --git a/PC/_msi.c b/PC/_msi.c index a6a12e2010738b..cc4d941ffb1a90 100644 --- a/PC/_msi.c +++ b/PC/_msi.c @@ -545,7 +545,7 @@ summary_getproperty(msiobj* si, PyObject *args) FILETIME fval; char sbuf[1000]; char *sval = sbuf; - DWORD ssize = sizeof(sval); + DWORD ssize = sizeof(sbuf); if (!PyArg_ParseTuple(args, "i:GetProperty", &field)) return NULL; @@ -553,6 +553,7 @@ summary_getproperty(msiobj* si, PyObject *args) status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival, &fval, sval, &ssize); if (status == ERROR_MORE_DATA) { + ssize++; sval = malloc(ssize); status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival, &fval, sval, &ssize); From 5291f2c995827820d90045a85c84cea26605f8bc Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Thu, 23 Nov 2017 18:14:17 +0800 Subject: [PATCH 2/2] Improve malloc/free call in summary_getproperty() This makes the malloc/free calls more trackable even when more types are added to MsiSummaryInfoGetProperty. --- PC/_msi.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/PC/_msi.c b/PC/_msi.c index cc4d941ffb1a90..c575d8149a2e35 100644 --- a/PC/_msi.c +++ b/PC/_msi.c @@ -560,19 +560,25 @@ summary_getproperty(msiobj* si, PyObject *args) } switch(type) { - case VT_I2: case VT_I4: - return PyLong_FromLong(ival); + case VT_I2: + case VT_I4: + result = PyLong_FromLong(ival); + break; case VT_FILETIME: PyErr_SetString(PyExc_NotImplementedError, "FILETIME result"); - return NULL; + result = NULL; + break; case VT_LPSTR: result = PyBytes_FromStringAndSize(sval, ssize); - if (sval != sbuf) - free(sval); - return result; + break; + default: + PyErr_Format(PyExc_NotImplementedError, "result of type %d", type); + result = NULL; + break; } - PyErr_Format(PyExc_NotImplementedError, "result of type %d", type); - return NULL; + if (sval != sbuf) + free(sval); + return result; } static PyObject*