@ -491,7 +491,7 @@ PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)
}
}
else
else
{
{
attval - > value = ( char * ) pqResultAlloc ( res , len + 1 , true ) ;
attval - > value = ( char * ) pqResultAlloc ( res , ( size_t ) len + 1 , true ) ;
if ( ! attval - > value )
if ( ! attval - > value )
goto fail ;
goto fail ;
attval - > len = len ;
attval - > len = len ;
@ -579,8 +579,13 @@ pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary)
*/
*/
if ( nBytes > = PGRESULT_SEP_ALLOC_THRESHOLD )
if ( nBytes > = PGRESULT_SEP_ALLOC_THRESHOLD )
{
{
size_t alloc_size = nBytes + PGRESULT_BLOCK_OVERHEAD ;
size_t alloc_size ;
/* Don't wrap around with overly large requests. */
if ( nBytes > SIZE_MAX - PGRESULT_BLOCK_OVERHEAD )
return NULL ;
alloc_size = nBytes + PGRESULT_BLOCK_OVERHEAD ;
block = ( PGresult_data * ) malloc ( alloc_size ) ;
block = ( PGresult_data * ) malloc ( alloc_size ) ;
if ( ! block )
if ( ! block )
return NULL ;
return NULL ;
@ -1156,7 +1161,7 @@ pqRowProcessor(PGconn *conn, const char **errmsgp)
bool isbinary = ( res - > attDescs [ i ] . format ! = 0 ) ;
bool isbinary = ( res - > attDescs [ i ] . format ! = 0 ) ;
char * val ;
char * val ;
val = ( char * ) pqResultAlloc ( res , clen + 1 , isbinary ) ;
val = ( char * ) pqResultAlloc ( res , ( size_t ) clen + 1 , isbinary ) ;
if ( val = = NULL )
if ( val = = NULL )
goto fail ;
goto fail ;
@ -4084,6 +4089,27 @@ PQescapeString(char *to, const char *from, size_t length)
}
}
/*
* Frontend version of the backend ' s add_size ( ) , intended to be API - compatible
* with the pg_add_ * _overflow ( ) helpers . Stores the result into * dst on success .
* Returns true instead if the addition overflows .
*
* TODO : move to common / int . h
*/
static bool
add_size_overflow ( size_t s1 , size_t s2 , size_t * dst )
{
size_t result ;
result = s1 + s2 ;
if ( result < s1 | | result < s2 )
return true ;
* dst = result ;
return false ;
}
/*
/*
* Escape arbitrary strings . If as_ident is true , we escape the result
* Escape arbitrary strings . If as_ident is true , we escape the result
* as an identifier ; if false , as a literal . The result is returned in
* as an identifier ; if false , as a literal . The result is returned in
@ -4096,8 +4122,8 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
const char * s ;
const char * s ;
char * result ;
char * result ;
char * rp ;
char * rp ;
int num_quotes = 0 ; /* single or double, depending on as_ident */
size_t num_quotes = 0 ; /* single or double, depending on as_ident */
int num_backslashes = 0 ;
size_t num_backslashes = 0 ;
size_t input_len = strnlen ( str , len ) ;
size_t input_len = strnlen ( str , len ) ;
size_t result_size ;
size_t result_size ;
char quote_char = as_ident ? ' " ' : ' \' ' ;
char quote_char = as_ident ? ' " ' : ' \' ' ;
@ -4163,10 +4189,21 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
}
}
}
}
/* Allocate output buffer. */
/*
result_size = input_len + num_quotes + 3 ; /* two quotes, plus a NUL */
* Allocate output buffer . Protect against overflow , in case the caller
* has allocated a large fraction of the available size_t .
*/
if ( add_size_overflow ( input_len , num_quotes , & result_size ) | |
add_size_overflow ( result_size , 3 , & result_size ) ) /* two quotes plus a NUL */
goto overflow ;
if ( ! as_ident & & num_backslashes > 0 )
if ( ! as_ident & & num_backslashes > 0 )
result_size + = num_backslashes + 2 ;
{
if ( add_size_overflow ( result_size , num_backslashes , & result_size ) | |
add_size_overflow ( result_size , 2 , & result_size ) ) /* for " E" prefix */
goto overflow ;
}
result = rp = ( char * ) malloc ( result_size ) ;
result = rp = ( char * ) malloc ( result_size ) ;
if ( rp = = NULL )
if ( rp = = NULL )
{
{
@ -4240,6 +4277,12 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
* rp = ' \0 ' ;
* rp = ' \0 ' ;
return result ;
return result ;
overflow :
appendPQExpBuffer ( & conn - > errorMessage ,
libpq_gettext ( " escaped string size exceeds the maximum allowed (%zu) \n " ) ,
SIZE_MAX ) ;
return NULL ;
}
}
char *
char *
@ -4305,16 +4348,25 @@ PQescapeByteaInternal(PGconn *conn,
unsigned char * result ;
unsigned char * result ;
size_t i ;
size_t i ;
size_t len ;
size_t len ;
size_t bslash_len = ( std_strings ? 1 : 2 ) ;
const size_t bslash_len = ( std_strings ? 1 : 2 ) ;
/*
/*
* empty string has 1 char ( ' \0 ' )
* Calculate the escaped length , watching for overflow as we do with
* PQescapeInternal ( ) . The following code relies on a small constant
* bslash_len so that small additions and multiplications don ' t need their
* own overflow checks .
*
* Start with the empty string , which has 1 char ( ' \0 ' ) .
*/
*/
len = 1 ;
len = 1 ;
if ( use_hex )
if ( use_hex )
{
{
len + = bslash_len + 1 + 2 * from_length ;
/* We prepend "\x" and double each input character. */
if ( add_size_overflow ( len , bslash_len + 1 , & len ) | |
add_size_overflow ( len , from_length , & len ) | |
add_size_overflow ( len , from_length , & len ) )
goto overflow ;
}
}
else
else
{
{
@ -4322,13 +4374,25 @@ PQescapeByteaInternal(PGconn *conn,
for ( i = from_length ; i > 0 ; i - - , vp + + )
for ( i = from_length ; i > 0 ; i - - , vp + + )
{
{
if ( * vp < 0x20 | | * vp > 0x7e )
if ( * vp < 0x20 | | * vp > 0x7e )
len + = bslash_len + 3 ;
{
if ( add_size_overflow ( len , bslash_len + 3 , & len ) ) /* octal "\ooo" */
goto overflow ;
}
else if ( * vp = = ' \' ' )
else if ( * vp = = ' \' ' )
len + = 2 ;
{
if ( add_size_overflow ( len , 2 , & len ) ) /* double each quote */
goto overflow ;
}
else if ( * vp = = ' \\ ' )
else if ( * vp = = ' \\ ' )
len + = bslash_len + bslash_len ;
{
if ( add_size_overflow ( len , bslash_len * 2 , & len ) ) /* double each backslash */
goto overflow ;
}
else
else
len + + ;
{
if ( add_size_overflow ( len , 1 , & len ) )
goto overflow ;
}
}
}
}
}
@ -4390,6 +4454,13 @@ PQescapeByteaInternal(PGconn *conn,
* rp = ' \0 ' ;
* rp = ' \0 ' ;
return result ;
return result ;
overflow :
if ( conn )
appendPQExpBuffer ( & conn - > errorMessage ,
libpq_gettext ( " escaped bytea size exceeds the maximum allowed (%zu) \n " ) ,
SIZE_MAX ) ;
return NULL ;
}
}
unsigned char *
unsigned char *