mirror of
				https://github.com/psycopg/psycopg2.git
				synced 2025-11-04 01:37:31 +03:00 
			
		
		
		
	Fixed reference leak with arguments referenced more than once in queries
Plus, some more care in objects life cycle, mostly in exceptions handling. Closes ticket #81.
This commit is contained in:
		
							parent
							
								
									cdb19a2329
								
							
						
					
					
						commit
						ad3a198919
					
				
							
								
								
									
										2
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								NEWS
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -18,6 +18,8 @@ What's new in psycopg 2.4.3
 | 
			
		|||
  - Fixed interaction between RealDictCursor and named cursors
 | 
			
		||||
    (ticket #67).
 | 
			
		||||
  - Dropped limit on the columns length in COPY operations (ticket #68).
 | 
			
		||||
  - Fixed reference leak with arguments referenced more than once
 | 
			
		||||
    in queries (ticket #81).
 | 
			
		||||
  - Fixed typecasting of arrays containing consecutive backslashes.
 | 
			
		||||
  - 'errorcodes' map updated to PostgreSQL 9.1.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -123,23 +123,29 @@ _mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new)
 | 
			
		|||
            for (d = c + 1; *d && *d != ')' && *d != '%'; d++);
 | 
			
		||||
 | 
			
		||||
            if (*d == ')') {
 | 
			
		||||
                key = Text_FromUTF8AndSize(c+1, (Py_ssize_t) (d-c-1));
 | 
			
		||||
                value = PyObject_GetItem(var, key);
 | 
			
		||||
                /* key has refcnt 1, value the original value + 1 */
 | 
			
		||||
                if (!(key = Text_FromUTF8AndSize(c+1, (Py_ssize_t)(d-c-1)))) {
 | 
			
		||||
                    Py_XDECREF(n);
 | 
			
		||||
                    return -1;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                /*  if value is NULL we did not find the key (or this is not a
 | 
			
		||||
                    dictionary): let python raise a KeyError */
 | 
			
		||||
                if (value == NULL) {
 | 
			
		||||
                if (!(value = PyObject_GetItem(var, key))) {
 | 
			
		||||
                    Py_DECREF(key); /* destroy key */
 | 
			
		||||
                    Py_XDECREF(n);  /* destroy n */
 | 
			
		||||
                    return -1;
 | 
			
		||||
                }
 | 
			
		||||
                /* key has refcnt 1, value the original value + 1 */
 | 
			
		||||
 | 
			
		||||
                Dprintf("_mogrify: value refcnt: "
 | 
			
		||||
                  FORMAT_CODE_PY_SSIZE_T " (+1)", Py_REFCNT(value));
 | 
			
		||||
 | 
			
		||||
                if (n == NULL) {
 | 
			
		||||
                    n = PyDict_New();
 | 
			
		||||
                    if (!(n = PyDict_New())) {
 | 
			
		||||
                        Py_DECREF(key);
 | 
			
		||||
                        Py_DECREF(value);
 | 
			
		||||
                        return -1;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (0 == PyDict_Contains(n, key)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -156,24 +162,22 @@ _mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new)
 | 
			
		|||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        t = microprotocol_getquoted(value, curs->conn);
 | 
			
		||||
 | 
			
		||||
                        if (t != NULL) {
 | 
			
		||||
                            PyDict_SetItem(n, key, t);
 | 
			
		||||
                            /* both key and t refcnt +1, key is at 2 now */
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            /* no adapter found, raise a BIG exception */
 | 
			
		||||
                            Py_XDECREF(value);
 | 
			
		||||
                            Py_DECREF(key);
 | 
			
		||||
                            Py_DECREF(value);
 | 
			
		||||
                            Py_DECREF(n);
 | 
			
		||||
                            return -1;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Py_XDECREF(t); /* t dies here */
 | 
			
		||||
                    /* after the DECREF value has the original refcnt plus 1
 | 
			
		||||
                       if it was added to the dictionary directly; good */
 | 
			
		||||
                    Py_XDECREF(value);
 | 
			
		||||
                }
 | 
			
		||||
                Py_DECREF(value);
 | 
			
		||||
                Py_DECREF(key); /* key has the original refcnt now */
 | 
			
		||||
                Dprintf("_mogrify: after value refcnt: "
 | 
			
		||||
                    FORMAT_CODE_PY_SSIZE_T, Py_REFCNT(value));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,6 +97,18 @@ class CursorTests(unittest.TestCase):
 | 
			
		|||
        self.assertEqual(b('SELECT 10.3;'),
 | 
			
		||||
            cur.mogrify("SELECT %s;", (Decimal("10.3"),)))
 | 
			
		||||
 | 
			
		||||
    def test_mogrify_leak_on_multiple_reference(self):
 | 
			
		||||
        # issue #81: reference leak when a parameter value is referenced
 | 
			
		||||
        # more than once from a dict.
 | 
			
		||||
        cur = self.conn.cursor()
 | 
			
		||||
        i = lambda x: x
 | 
			
		||||
        foo = i('foo') * 10
 | 
			
		||||
        import sys
 | 
			
		||||
        nref1 = sys.getrefcount(foo)
 | 
			
		||||
        cur.mogrify("select %(foo)s, %(foo)s, %(foo)s", {'foo': foo})
 | 
			
		||||
        nref2 = sys.getrefcount(foo)
 | 
			
		||||
        self.assertEqual(nref1, nref2)
 | 
			
		||||
 | 
			
		||||
    def test_bad_placeholder(self):
 | 
			
		||||
        cur = self.conn.cursor()
 | 
			
		||||
        self.assertRaises(psycopg2.ProgrammingError,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user