Package: diffutils;
Reported by: Peter Dyballa <Peter_Dyballa <at> Web.DE>
Date: Wed, 16 Apr 2025 10:55:02 UTC
Severity: normal
View this message in rfc822 format
From: Peter Dyballa <Peter_Dyballa <at> Web.DE> To: Paul Eggert <eggert <at> cs.ucla.edu> Cc: 77840 <at> debbugs.gnu.org Subject: bug#77840: [bug-diffutils] bug#77840: Testing diffutils 3.12 on PPC Mac OS X 10.4.11, Tiger, produces so many failures Date: Fri, 20 Jun 2025 12:01:56 +0200
In diff.c:882 we have in main(): exit_status = compare_files (&noparent, de_unknowns, argv[optind], argv[optind + 1]);. This function is defined in diff.c, starting at lines #1376 (comments) or #1387 (code). It has close to its end on line #1633/1634: if (status == EXIT_SUCCESS) status = compare_prepped_files (parent, &cmp, O_RDONLY | oflags); compare_prepped_files() is new, compared to diffutils 3.10, and is also defined in diff.c, lines #1158 (comments) or #1162 (code). It has at its end on line #1372: return diff_2_files (cmp); This function is defined in analyze.c, starting at lines #451 (comments) or #452 (code). It has inside a switch statement 621 switch (output_style) 622 { 623 case OUTPUT_CONTEXT: 624 print_context_script (script, false); 625 break; 626 627 case OUTPUT_UNIFIED: 628 print_context_script (script, true); 629 break; So it's the print_context_script() branch of function calls that contains the faulty code. It's defined in context.c, starting at lines #109 (comments) or #111 (code). It makes a comparison between context and unified diff: 123 if (unidiff) 124 print_script (script, find_hunk, pr_unidiff_hunk); 125 else 126 print_script (script, find_hunk, pr_context_hunk); The array script was created before, it is created in (almost?) any case: context.c:124: print_script (script, find_hunk, pr_unidiff_hunk); context.c:126: print_script (script, find_hunk, pr_context_hunk); ed.c:33: print_script (script, find_change, print_ed_hunk); ed.c:97: print_script (script, find_change, pr_forward_ed_hunk); ed.c:136: print_script (script, find_change, print_rcs_hunk); ifdef.c:54: print_script (script, find_change, print_ifdef_hunk); normal.c:31: print_script (script, find_change, print_normal_hunk); side.c:41: print_script (script, find_change, print_sdiff_hunk); The function print_script() is defined in util.c, starting at lines #941 (comments) or #952 (code), find_hunk() and find_change() are functions (find_change() is defined in util.c, find_hunk() is defined in context.c) and presumingly OK (although I could see contradicting line numbers in output?). The third argument of print_script() varies a bit in name (pr_ vs. print_), they are defined in different files, each working on a particular diff case (ed script, "normal", side-by-side, and context/unified). So it's possible that pr_unidiff_hunk and pr_context_hunk can have the faulty code, twice? find_hunk() has only one argument (struct change *script), works on its contents and returns the finished struct. Rather negligible: 429 /* Scan a (forward-ordered) edit script for the first place that more than 430 2*CONTEXT unchanged lines appear, and return a pointer 431 to the 'struct change' for the last change before those lines. */ 432 433 static struct change * ATTRIBUTE_PURE 434 find_hunk (struct change *script) 435 { 436 /* Threshold distance is CONTEXT if the second change is ignorable, 437 min (2 * CONTEXT + 1, LIN_MAX) otherwise. */ 438 lin ignorable_threshold = context; 439 lin non_ignorable_threshold = (ckd_mul (&non_ignorable_threshold, context, 2) 440 ? LIN_MAX 441 : non_ignorable_threshold + 1); 442 443 for (struct change *next; ; script = next) 444 { 445 next = script->link; 446 /* Compute number of first line in each file beyond this changed. */ 447 lin top0 = script->line0 + script->deleted; 448 lin top1 = script->line1 + script->inserted; 449 lin thresh = (next && next->ignore 450 ? ignorable_threshold 451 : non_ignorable_threshold); 452 /* It is not supposed to matter which file we check in the end-test. */ 453 dassert (!next || next->line0 - top0 == next->line1 - top1); 454 455 /* Keep going if less than THRESH lines elapse 456 before the affected line. */ 457 if (!next || thresh <= next->line0 - top0) 458 return script; 459 } 460 } pr_context_hunk()/pr_unidiff_hunk() make internal use of the curr struct, change its contents, obviously not a file name or such. Instead they call begin_output() – a function that is also used in the other diff cases… But it has a special clause near its end: 886 /* A special header is needed at the beginning of context output. */ 887 if (output_style == OUTPUT_CONTEXT || output_style == OUTPUT_UNIFIED) 888 print_context_header (curr.file, names, 889 output_style == OUTPUT_UNIFIED); Only in our two faulty cases, unified and context diff, the malfunction happens. So 'print_context_header()' must contain the bug, but it's too simple, in context.c: 92 /* Print a header for a context diff, with the file names and dates. */ 93 94 void 95 print_context_header (struct file_data inf[], char const *const *names, bool unidiff) 96 { 97 if (unidiff) 98 { 99 print_context_label ("---", &inf[0], names[0], file_label[0]); 100 print_context_label ("+++", &inf[1], names[1], file_label[1]); 101 } 102 else 103 { 104 print_context_label ("***", &inf[0], names[0], file_label[0]); 105 print_context_label ("---", &inf[1], names[1], file_label[1]); 106 } 107 } This function has the declaration 'char const *const *names', but definition of 'print_context_label()' starts with: 40 static void 41 print_context_label (char const *mark, 42 struct file_data *inf, 43 char const *name, 44 char const *label) 45 { To me "char const *const *" is not the same as "char const *" – could be for PPC Mac OS X 10.4.11 too? I do not understand these code differences anyway. Comparing the function definition in both versions 3.12 and 3.10 I see that time is handled differently – cause found? In the end both functions simply have: set_color_context (RESET_CONTEXT); putc ('\n', outfile); The newer version has 24 int nsec = ts.tv_nsec; On Tiger /usr/include/time.h has: 87 #ifndef _TIMESPEC 88 #define _TIMESPEC 89 struct timespec { 90 time_t tv_sec; /* seconds */ 91 long tv_nsec; /* and nanoseconds */ 92 }; 93 #endif 94 95 struct tm { 96 int tm_sec; /* seconds after the minute [0-60] */ 97 int tm_min; /* minutes after the hour [0-59] */ 98 int tm_hour; /* hours since midnight [0-23] */ 99 int tm_mday; /* day of the month [1-31] */ 100 int tm_mon; /* months since January [0-11] */ 101 int tm_year; /* years since 1900 */ 102 int tm_wday; /* days since Sunday [0-6] */ 103 int tm_yday; /* days since January 1 [0-365] */ 104 int tm_isdst; /* Daylight Savings Time flag */ 105 long tm_gmtoff; /* offset from CUT in seconds */ 106 char *tm_zone; /* timezone abbreviation */ 107 }; nstrftime() is not known on Tiger, but defined in lib/strftime.h. I'll check that area, either (much) later or tomorrow! -- Greetings Pete We also sponsor National Invisible Chronic Illness Awareness Week annually in September. Join the millions!
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.