@@ -375,6 +375,23 @@ static void parseProperty(Map<String, String> r, final XMLStreamReader reader, S
375375 }
376376 }
377377
378+ /**
379+ * Cleans up a truncated string, that might contain unpaired surrogates
380+ * @param str input string
381+ * @return input string, possibly truncated to avoid unpaired surrogates
382+ */
383+ static CharSequence cleanupTruncated (CharSequence str ) {
384+ // remove unpaired trailing surrogates at the start
385+ if (str .length () > 0 && Character .isLowSurrogate (str .charAt (0 ))) {
386+ str = str .subSequence (1 , str .length ());
387+ }
388+ // remove unpaired leading surrogates at the end
389+ if (str .length () > 0 && Character .isHighSurrogate (str .charAt (str .length () - 1 ))) {
390+ str = str .subSequence (0 , str .length () - 1 );
391+ }
392+ return str ;
393+ }
394+
378395 static String possiblyTrimStdio (
379396 Collection <CaseResult > results , StdioRetention stdioRetention , String stdio ) { // HUDSON-6516
380397 if (stdio == null ) {
@@ -391,8 +408,8 @@ static String possiblyTrimStdio(
391408 if (middle <= 0 ) {
392409 return stdio ;
393410 }
394- return stdio .subSequence (0 , halfMaxSize ) + "\n ...[truncated " + middle + " chars]...\n "
395- + stdio .subSequence (len - halfMaxSize , len );
411+ return cleanupTruncated ( stdio .subSequence (0 , halfMaxSize ) ) + "\n ...[truncated " + middle + " chars]...\n "
412+ + cleanupTruncated ( stdio .subSequence (len - halfMaxSize , len ) );
396413 }
397414
398415 static String fixNULs (String stdio ) { // JENKINS-71139
@@ -432,7 +449,7 @@ static String possiblyTrimStdio(Collection<CaseResult> results, StdioRetention s
432449 return FileUtils .readFileToString (stdio );
433450 }
434451
435- return head + "\n ...[truncated " + middle + " bytes]...\n " + tail ;
452+ return cleanupTruncated ( head ) + "\n ...[truncated " + middle + " bytes]...\n " + cleanupTruncated ( tail ) ;
436453 }
437454
438455 private static final int HALF_MAX_SIZE = 500 ;
0 commit comments