@@ -6119,6 +6119,9 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin
6119
6119
unsigned char * in = (unsigned char * )ZSTR_VAL (input );
6120
6120
size_t in_len = ZSTR_LEN (input );
6121
6121
6122
+ ZEND_ASSERT (outcode -> mime_name != NULL );
6123
+ ZEND_ASSERT (outcode -> mime_name [0 ] != '\0' );
6124
+
6122
6125
if (!in_len ) {
6123
6126
return zend_empty_string ;
6124
6127
}
@@ -6141,7 +6144,8 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin
6141
6144
unsigned int state = 0 ;
6142
6145
/* wchar_buf should be big enough that when it is full, we definitely have enough
6143
6146
* wchars to fill an entire line of output */
6144
- uint32_t wchar_buf [80 ];
6147
+ const size_t wchar_buf_len = 90 ;
6148
+ uint32_t wchar_buf [wchar_buf_len ];
6145
6149
uint32_t * p , * e ;
6146
6150
/* What part of wchar_buf is filled with still-unprocessed data which should not
6147
6151
* be overwritten? */
@@ -6152,7 +6156,7 @@ static zend_string* mb_mime_header_encode(zend_string *input, const mbfl_encodin
6152
6156
* spaces), just pass it through unchanged */
6153
6157
bool checking_leading_spaces = true;
6154
6158
while (in_len ) {
6155
- size_t out_len = incode -> to_wchar (& in , & in_len , wchar_buf , 80 , & state );
6159
+ size_t out_len = incode -> to_wchar (& in , & in_len , wchar_buf , wchar_buf_len , & state );
6156
6160
p = wchar_buf ;
6157
6161
e = wchar_buf + out_len ;
6158
6162
@@ -6186,9 +6190,9 @@ no_passthrough: ;
6186
6190
* do so all the way to the end of the string */
6187
6191
while (in_len ) {
6188
6192
/* Decode part of the input string, refill wchar_buf */
6189
- ZEND_ASSERT (offset < 80 );
6190
- size_t out_len = incode -> to_wchar (& in , & in_len , wchar_buf + offset , 80 - offset , & state );
6191
- ZEND_ASSERT (out_len <= 80 - offset );
6193
+ ZEND_ASSERT (offset + MBSTRING_MIN_WCHAR_BUFSIZE <= wchar_buf_len );
6194
+ size_t out_len = incode -> to_wchar (& in , & in_len , wchar_buf + offset , wchar_buf_len - offset , & state );
6195
+ ZEND_ASSERT (out_len <= wchar_buf_len - offset );
6192
6196
p = wchar_buf ;
6193
6197
e = wchar_buf + offset + out_len ;
6194
6198
/* ASCII output is broken into space-delimited 'words'
@@ -6209,6 +6213,7 @@ no_passthrough: ;
6209
6213
* If we are already too far along on a line to include Base64/QPrint encoded data
6210
6214
* on the same line (without overrunning max line length), then add a line feed
6211
6215
* right now */
6216
+ feed_and_mime_encode :
6212
6217
if (mb_convert_buf_len (& buf ) - line_start + indent + strlen (outcode -> mime_name ) > 55 ) {
6213
6218
MB_CONVERT_BUF_ENSURE (& buf , buf .out , buf .limit , (e - word_start ) + linefeed_len + 1 );
6214
6219
buf .out = mb_convert_buf_appendn (buf .out , linefeed , linefeed_len );
@@ -6246,7 +6251,13 @@ no_passthrough: ;
6246
6251
6247
6252
if (in_len ) {
6248
6253
/* Copy chars which are part of an incomplete 'word' to the beginning
6249
- * of wchar_buf and reprocess them on the next iteration */
6254
+ * of wchar_buf and reprocess them on the next iteration.
6255
+ * But first make sure that the incomplete 'word' isn't so big that
6256
+ * there will be no space to add any more decoded wchars in the buffer
6257
+ * (which could lead to an infinite loop) */
6258
+ if ((word_start - wchar_buf ) < MBSTRING_MIN_WCHAR_BUFSIZE ) {
6259
+ goto feed_and_mime_encode ;
6260
+ }
6250
6261
offset = e - word_start ;
6251
6262
if (offset ) {
6252
6263
memmove (wchar_buf , word_start , offset * sizeof (uint32_t ));
@@ -6288,17 +6299,17 @@ mime_encoding_needed: ;
6288
6299
6289
6300
/* Do we need to refill wchar_buf to make sure we don't run out of wchars
6290
6301
* in the middle of a line? */
6291
- if (p == wchar_buf ) {
6302
+ offset = e - p ;
6303
+ if (wchar_buf_len - offset < MBSTRING_MIN_WCHAR_BUFSIZE ) {
6292
6304
goto start_new_line ;
6293
6305
}
6294
- offset = e - p ;
6295
6306
memmove (wchar_buf , p , offset * sizeof (uint32_t ));
6296
6307
6297
6308
while (true) {
6298
6309
refill_wchar_buf : ;
6299
- ZEND_ASSERT (offset < 80 );
6300
- size_t out_len = incode -> to_wchar (& in , & in_len , wchar_buf + offset , 80 - offset , & state );
6301
- ZEND_ASSERT (out_len <= 80 - offset );
6310
+ ZEND_ASSERT (offset + MBSTRING_MIN_WCHAR_BUFSIZE <= wchar_buf_len );
6311
+ size_t out_len = incode -> to_wchar (& in , & in_len , wchar_buf + offset , wchar_buf_len - offset , & state );
6312
+ ZEND_ASSERT (out_len <= wchar_buf_len - offset );
6302
6313
p = wchar_buf ;
6303
6314
e = wchar_buf + offset + out_len ;
6304
6315
@@ -6373,22 +6384,18 @@ start_new_line: ;
6373
6384
6374
6385
indent = 0 ; /* Indent argument must only affect the first line */
6375
6386
6376
- if (in_len ) {
6377
- /* We still have more of input string remaining to decode */
6387
+ if (in_len || p < e ) {
6388
+ /* We still have more input to process */
6378
6389
buf .out = mb_convert_buf_appendn (buf .out , linefeed , linefeed_len );
6379
6390
buf .out = mb_convert_buf_add (buf .out , ' ' );
6380
6391
line_start = mb_convert_buf_len (& buf );
6381
- /* Copy remaining wchars to beginning of buffer so they will be
6382
- * processed on the next iteration of outer 'do' loop */
6383
6392
offset = e - p ;
6384
- memmove (wchar_buf , p , offset * sizeof (uint32_t ));
6385
- goto refill_wchar_buf ;
6386
- } else if (p < e ) {
6387
- /* Input string is finished, but we still have trailing wchars
6388
- * remaining to be processed in wchar_buf */
6389
- buf .out = mb_convert_buf_appendn (buf .out , linefeed , linefeed_len );
6390
- buf .out = mb_convert_buf_add (buf .out , ' ' );
6391
- line_start = mb_convert_buf_len (& buf );
6393
+ if (in_len && (wchar_buf_len - offset >= MBSTRING_MIN_WCHAR_BUFSIZE )) {
6394
+ /* Copy any remaining wchars to beginning of buffer and refill
6395
+ * the rest of the buffer */
6396
+ memmove (wchar_buf , p , offset * sizeof (uint32_t ));
6397
+ goto refill_wchar_buf ;
6398
+ }
6392
6399
goto start_new_line ;
6393
6400
} else {
6394
6401
/* We are done! */
@@ -6426,7 +6433,7 @@ PHP_FUNCTION(mb_encode_mimeheader)
6426
6433
charset = php_mb_get_encoding (charset_name , 2 );
6427
6434
if (!charset ) {
6428
6435
RETURN_THROWS ();
6429
- } else if (charset -> mime_name == NULL || charset -> mime_name [0 ] == '\0' ) {
6436
+ } else if (charset -> mime_name == NULL || charset -> mime_name [0 ] == '\0' || charset == & mbfl_encoding_qprint ) {
6430
6437
zend_argument_value_error (2 , "\"%s\" cannot be used for MIME header encoding" , ZSTR_VAL (charset_name ));
6431
6438
RETURN_THROWS ();
6432
6439
}
0 commit comments