On Tue, 10 Nov 2015, Serguey Parkhomovsky wrote:
> Some of the comparator functions in gprof(1) have incompatible pointer
> types and generate compiler warnings. The following diff fixes the
> problem.
Your diff is a step forward, yes. I think it's slightly improved to add
more 'const's so that the casts in topcmp(), timecmp(), and namecmp() can
be eliminated, ala:
+ const nltype * const *npp1 = v1;
+ const nltype * const *npp2 = v2;
Beyond that, looking at those compare functions I see at least two
additional problems.
The underlying requirement is that the comparison function provided to
qsort() must be _consistent_. This means that compare(A,B) and
compare(B,A) must either both be zero or have opposite signs. If that's
not true, then qsort()'s behavior isn't defined: some versions have
segfaulted or accessed beyond the ends of the provided array when that
happens!
So, given that understanding:
1) topcmp() assumes the subtraction can't overflow; if it does then it's
straight up undefined behavior (signed overflow). If your system
defined that as 2's-complement wraparound, then it's still an
inconsistent comparison!
2) totalcmp(A,B) and totalcmp(B,A) both return <0 if both A and B have
name==0 and cycleno!=0, and they both return >0 if both A and B have
naem==0 and cycleno==0, violating the consistency requirement.
Diff below extends yours to fix those as well. Does this still work for
you?
Anyone care to review my changes here to verify I got the directions on
the comparisons to match the original code?
Philip
Index: arcs.c
===================================================================
RCS file: /data/src/openbsd/src/usr.bin/gprof/arcs.c,v
retrieving revision 1.13
diff -u -p -r1.13 arcs.c
--- arcs.c 20 Aug 2015 22:32:41 -0000 1.13
+++ arcs.c 15 Nov 2015 06:51:44 -0000
@@ -95,9 +95,14 @@ addarc(nltype *parentp, nltype *childp,
nltype **topsortnlp;
int
-topcmp(nltype **npp1, nltype **npp2)
+topcmp(const void *v1, const void *v2)
{
- return (*npp1) -> toporder - (*npp2) -> toporder;
+ const nltype * const *npp1 = v1;
+ const nltype * const *npp2 = v2;
+
+ if ((*npp1) -> toporder < (*npp2) -> toporder)
+ return -1;
+ return (*npp1) -> toporder > (*npp2) -> toporder;
}
nltype **
Index: gprof.h
===================================================================
RCS file: /data/src/openbsd/src/usr.bin/gprof/gprof.h,v
retrieving revision 1.14
diff -u -p -r1.14 gprof.h
--- gprof.h 19 Oct 2013 13:51:40 -0000 1.14
+++ gprof.h 15 Nov 2015 06:25:33 -0000
@@ -281,10 +281,10 @@ void sortchildren(nltype *);
void sortmembers(nltype *);
void sortparents(nltype *);
void tally(struct rawarc *);
-int timecmp(nltype **, nltype **);
+int timecmp(const void *, const void *);
void timepropagate(nltype *);
-int topcmp(nltype **, nltype **);
-int totalcmp(nltype **, nltype **);
+int topcmp(const void *, const void *);
+int totalcmp(const void *, const void *);
#define LESSTHAN -1
#define EQUALTO 0
Index: printgprof.c
===================================================================
RCS file: /data/src/openbsd/src/usr.bin/gprof/printgprof.c,v
retrieving revision 1.13
diff -u -p -r1.13 printgprof.c
--- printgprof.c 20 Aug 2015 22:32:41 -0000 1.13
+++ printgprof.c 15 Nov 2015 06:52:09 -0000
@@ -35,7 +35,7 @@
#include "gprof.h"
#include "pathnames.h"
-int namecmp(nltype **, nltype **);
+int namecmp(const void *, const void *);
void
printprof()
@@ -66,21 +66,19 @@ printprof()
}
int
-timecmp(nltype **npp1, nltype **npp2)
+timecmp(const void *v1, const void *v2)
{
- double timediff;
- long calldiff;
+ const nltype * const *npp1 = v1;
+ const nltype * const *npp2 = v2;
- timediff = (*npp2) -> time - (*npp1) -> time;
- if ( timediff > 0.0 )
+ if ((*npp2) -> time < (*npp1) -> time)
+ return -1;
+ if ((*npp2) -> time > (*npp1) -> time)
return 1 ;
- if ( timediff < 0.0 )
+ if ((*npp2) -> ncall < (*npp1) -> ncall)
return -1;
- calldiff = (*npp2) -> ncall - (*npp1) -> ncall;
- if ( calldiff > 0 )
+ if ((*npp2) -> ncall > (*npp1) -> ncall)
return 1;
- if ( calldiff < 0 )
- return -1;
return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
}
@@ -233,26 +231,32 @@ printgprof(nltype **timesortnlp)
* all else being equal, sort by names.
*/
int
-totalcmp(nltype **npp1, nltype **npp2)
+totalcmp(const void *v1, const void *v2)
{
- nltype *np1 = *npp1;
- nltype *np2 = *npp2;
- double diff;
-
- diff = ( np1 -> propself + np1 -> propchild )
- - ( np2 -> propself + np2 -> propchild );
- if ( diff < 0.0 )
+ const nltype *np1 = *(const nltype **)v1;
+ const nltype *np2 = *(const nltype **)v2;
+ double t1, t2;
+
+ t1 = np1 -> propself + np1 -> propchild;
+ t2 = np2 -> propself + np2 -> propchild;
+ if (t2 > t1)
return 1;
- if ( diff > 0.0 )
+ if (t2 < t1)
return -1;
- if ( np1 -> name == 0 && np1 -> cycleno != 0 )
- return -1;
- if ( np2 -> name == 0 && np2 -> cycleno != 0 )
- return 1;
- if ( np1 -> name == 0 )
+
+ /* have to be careful to keep the sort consistent */
+ if ( np1 -> name == 0 && np1 -> cycleno != 0 ) {
+ if ( np2 -> name != 0 || np2 -> cycleno == 0 )
+ return 1;
+ } else if ( np2 -> name != 0 || np2 -> cycleno == 0 )
return -1;
- if ( np2 -> name == 0 )
+
+ if ( np1 -> name == 0 ) {
+ if ( np2 -> name != 0 )
+ return -1;
+ } else if ( np2 -> name == 0 )
return 1;
+
if ( *(np1 -> name) != '_' && *(np2 -> name) == '_' )
return -1;
if ( *(np1 -> name) == '_' && *(np2 -> name) != '_' )
@@ -642,8 +646,11 @@ printblurb(const char *blurbname)
}
int
-namecmp(nltype **npp1, nltype **npp2)
+namecmp(const void *v1, const void *v2)
{
+ const nltype * const *npp1 = v1;
+ const nltype * const *npp2 = v2;
+
return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
}