@@ -5858,6 +5858,9 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin
5858
5858
unsigned char * in = (unsigned char * )ZSTR_VAL (input );
5859
5859
size_t in_len = ZSTR_LEN (input );
5860
5860
5861
+ ZEND_ASSERT (outcode -> mime_name != NULL );
5862
+ ZEND_ASSERT (outcode -> mime_name [0 ] != '\0' );
5863
+
5861
5864
if (!in_len ) {
5862
5865
return zend_empty_string ;
5863
5866
}
@@ -5880,7 +5883,8 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin
5880
5883
unsigned int state = 0 ;
5881
5884
/* wchar_buf should be big enough that when it is full, we definitely have enough
5882
5885
* wchars to fill an entire line of output */
5883
- uint32_t wchar_buf [80 ];
5886
+ const size_t wchar_buf_len = 90 ;
5887
+ uint32_t wchar_buf [wchar_buf_len ];
5884
5888
uint32_t * p , * e ;
5885
5889
/* What part of wchar_buf is filled with still-unprocessed data which should not
5886
5890
* be overwritten? */
@@ -5891,7 +5895,7 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin
5891
5895
* spaces), just pass it through unchanged */
5892
5896
bool checking_leading_spaces = true;
5893
5897
while (in_len ) {
5894
- size_t out_len = incode -> to_wchar (& in , & in_len , wchar_buf , 80 , & state );
5898
+ size_t out_len = incode -> to_wchar (& in , & in_len , wchar_buf , wchar_buf_len , & state );
5895
5899
p = wchar_buf ;
5896
5900
e = wchar_buf + out_len ;
5897
5901
@@ -5925,9 +5929,9 @@ no_passthrough: ;
5925
5929
* do so all the way to the end of the string */
5926
5930
while (in_len ) {
5927
5931
/* Decode part of the input string, refill wchar_buf */
5928
- ZEND_ASSERT (offset < 80 );
5929
- size_t out_len = incode -> to_wchar (& in , & in_len , wchar_buf + offset , 80 - offset , & state );
5930
- ZEND_ASSERT (out_len <= 80 - offset );
5932
+ ZEND_ASSERT (offset + MBSTRING_MIN_WCHAR_BUFSIZE <= wchar_buf_len );
5933
+ size_t out_len = incode -> to_wchar (& in , & in_len , wchar_buf + offset , wchar_buf_len - offset , & state );
5934
+ ZEND_ASSERT (out_len <= wchar_buf_len - offset );
5931
5935
p = wchar_buf ;
5932
5936
e = wchar_buf + offset + out_len ;
5933
5937
/* ASCII output is broken into space-delimited 'words'
@@ -5948,6 +5952,7 @@ no_passthrough: ;
5948
5952
* If we are already too far along on a line to include Base64/QPrint encoded data
5949
5953
* on the same line (without overrunning max line length), then add a line feed
5950
5954
* right now */
5955
+ feed_and_mime_encode :
5951
5956
if (mb_convert_buf_len (& buf ) - line_start + indent + strlen (outcode -> mime_name ) > 55 ) {
5952
5957
MB_CONVERT_BUF_ENSURE (& buf , buf .out , buf .limit , (e - word_start ) + linefeed_len + 1 );
5953
5958
buf .out = mb_convert_buf_appendn (buf .out , linefeed , linefeed_len );
@@ -5985,7 +5990,13 @@ no_passthrough: ;
5985
5990
5986
5991
if (in_len ) {
5987
5992
/* Copy chars which are part of an incomplete 'word' to the beginning
5988
- * of wchar_buf and reprocess them on the next iteration */
5993
+ * of wchar_buf and reprocess them on the next iteration.
5994
+ * But first make sure that the incomplete 'word' isn't so big that
5995
+ * there will be no space to add any more decoded wchars in the buffer
5996
+ * (which could lead to an infinite loop) */
5997
+ if ((word_start - wchar_buf ) < MBSTRING_MIN_WCHAR_BUFSIZE ) {
5998
+ goto feed_and_mime_encode ;
5999
+ }
5989
6000
offset = e - word_start ;
5990
6001
if (offset ) {
5991
6002
memmove (wchar_buf , word_start , offset * sizeof (uint32_t ));
@@ -6027,17 +6038,17 @@ mime_encoding_needed: ;
6027
6038
6028
6039
/* Do we need to refill wchar_buf to make sure we don't run out of wchars
6029
6040
* in the middle of a line? */
6030
- if (p == wchar_buf ) {
6041
+ offset = e - p ;
6042
+ if (wchar_buf_len - offset < MBSTRING_MIN_WCHAR_BUFSIZE ) {
6031
6043
goto start_new_line ;
6032
6044
}
6033
- offset = e - p ;
6034
6045
memmove (wchar_buf , p , offset * sizeof (uint32_t ));
6035
6046
6036
6047
while (true) {
6037
6048
refill_wchar_buf : ;
6038
- ZEND_ASSERT (offset < 80 );
6039
- size_t out_len = incode -> to_wchar (& in , & in_len , wchar_buf + offset , 80 - offset , & state );
6040
- ZEND_ASSERT (out_len <= 80 - offset );
6049
+ ZEND_ASSERT (offset + MBSTRING_MIN_WCHAR_BUFSIZE <= wchar_buf_len );
6050
+ size_t out_len = incode -> to_wchar (& in , & in_len , wchar_buf + offset , wchar_buf_len - offset , & state );
6051
+ ZEND_ASSERT (out_len <= wchar_buf_len - offset );
6041
6052
p = wchar_buf ;
6042
6053
e = wchar_buf + offset + out_len ;
6043
6054
@@ -6112,22 +6123,18 @@ start_new_line: ;
6112
6123
6113
6124
indent = 0 ; /* Indent argument must only affect the first line */
6114
6125
6115
- if (in_len ) {
6116
- /* We still have more of input string remaining to decode */
6126
+ if (in_len || p < e ) {
6127
+ /* We still have more input to process */
6117
6128
buf .out = mb_convert_buf_appendn (buf .out , linefeed , linefeed_len );
6118
6129
buf .out = mb_convert_buf_add (buf .out , ' ' );
6119
6130
line_start = mb_convert_buf_len (& buf );
6120
- /* Copy remaining wchars to beginning of buffer so they will be
6121
- * processed on the next iteration of outer 'do' loop */
6122
6131
offset = e - p ;
6123
- memmove (wchar_buf , p , offset * sizeof (uint32_t ));
6124
- goto refill_wchar_buf ;
6125
- } else if (p < e ) {
6126
- /* Input string is finished, but we still have trailing wchars
6127
- * remaining to be processed in wchar_buf */
6128
- buf .out = mb_convert_buf_appendn (buf .out , linefeed , linefeed_len );
6129
- buf .out = mb_convert_buf_add (buf .out , ' ' );
6130
- line_start = mb_convert_buf_len (& buf );
6132
+ if (in_len && (wchar_buf_len - offset >= MBSTRING_MIN_WCHAR_BUFSIZE )) {
6133
+ /* Copy any remaining wchars to beginning of buffer and refill
6134
+ * the rest of the buffer */
6135
+ memmove (wchar_buf , p , offset * sizeof (uint32_t ));
6136
+ goto refill_wchar_buf ;
6137
+ }
6131
6138
goto start_new_line ;
6132
6139
} else {
6133
6140
/* We are done! */
@@ -6165,7 +6172,7 @@ PHP_FUNCTION(mb_encode_mimeheader)
6165
6172
charset = php_mb_get_encoding (charset_name , 2 );
6166
6173
if (!charset ) {
6167
6174
RETURN_THROWS ();
6168
- } else if (charset -> mime_name == NULL || charset -> mime_name [0 ] == '\0' ) {
6175
+ } else if (charset -> mime_name == NULL || charset -> mime_name [0 ] == '\0' || charset == & mbfl_encoding_qprint ) {
6169
6176
zend_argument_value_error (2 , "\"%s\" cannot be used for MIME header encoding" , ZSTR_VAL (charset_name ));
6170
6177
RETURN_THROWS ();
6171
6178
}
0 commit comments