@@ -760,6 +760,15 @@ static void k8s_kusts_free(k8s_kusts_t *ks) {
760760 * ks = (k8s_kusts_t ){0 };
761761}
762762
763+ /* qsort for this file's vectors. An empty vector's items is NULL, and glibc
764+ * declares qsort's base nonnull, so sorting it is undefined even with n == 0
765+ * (UBSan nonnull-attribute on Linux). Fewer than two elements need no sort. */
766+ static void k8s_qsort (void * base , size_t n , size_t size , int (* cmp )(const void * , const void * )) {
767+ if (base && n > 1 ) {
768+ qsort (base , n , size , cmp );
769+ }
770+ }
771+
763772static int k8s_cmp_str (const void * a , const void * b ) {
764773 return strcmp (* (const char * const * )a , * (const char * const * )b );
765774}
@@ -827,9 +836,9 @@ static void k8s_kusts_wire(cbm_pipeline_ctx_t *ctx, k8s_kusts_t *ks, CBMHashTabl
827836 }
828837 }
829838 for (int i = 0 ; i < ks -> count ; i ++ ) {
830- qsort (ks -> items [i ].files , (size_t )ks -> items [i ].file_n , sizeof (* ks -> items [i ].files ),
831- k8s_cmp_str );
832- qsort (ks -> items [i ].kids , (size_t )ks -> items [i ].kid_n , sizeof (int ), k8s_cmp_int );
839+ k8s_qsort (ks -> items [i ].files , (size_t )ks -> items [i ].file_n , sizeof (* ks -> items [i ].files ),
840+ k8s_cmp_str );
841+ k8s_qsort (ks -> items [i ].kids , (size_t )ks -> items [i ].kid_n , sizeof (int ), k8s_cmp_int );
833842 }
834843}
835844
@@ -1006,7 +1015,7 @@ static void k8s_bundles_build(cbm_pipeline_ctx_t *ctx, k8s_kusts_t *ks, k8s_bund
10061015 if (!b -> names || !b -> members || !b -> charts ) {
10071016 return ;
10081017 }
1009- qsort (ks -> items , (size_t )ks -> count , sizeof (* ks -> items ), k8s_cmp_kust );
1018+ k8s_qsort (ks -> items , (size_t )ks -> count , sizeof (* ks -> items ), k8s_cmp_kust );
10101019 CBMHashTable * by_path = cbm_ht_create (0 );
10111020 if (!by_path ) {
10121021 return ;
@@ -1345,7 +1354,7 @@ static void k8s_paths_sort_unique(k8s_paths_t *v) {
13451354 if (v -> count == 0 ) {
13461355 return ;
13471356 }
1348- qsort ((void * )v -> items , (size_t )v -> count , sizeof (* v -> items ), k8s_cmp_str );
1357+ k8s_qsort ((void * )v -> items , (size_t )v -> count , sizeof (* v -> items ), k8s_cmp_str );
13491358 int w = SKIP_ONE ;
13501359 for (int i = SKIP_ONE ; i < v -> count ; i ++ ) {
13511360 if (strcmp (v -> items [w - SKIP_ONE ], v -> items [i ]) != 0 ) {
@@ -1522,7 +1531,7 @@ static void k8s_deploys_build(cbm_pipeline_ctx_t *ctx, k8s_kusts_t *ks, k8s_bund
15221531 k8s_dir_members (ks , by_path , & manifests , f -> deploys [d ].dir , seen , d + SKIP_ONE ,
15231532 & members [d ], NULL );
15241533 }
1525- qsort (keys , un , sizeof (* keys ), k8s_cmp_deploy_key );
1534+ k8s_qsort (keys , un , sizeof (* keys ), k8s_cmp_deploy_key );
15261535 /* deploy d reaches deploy e when e sits in a manifest d applies */
15271536 for (int d = 0 ; d < n ; d ++ ) {
15281537 for (int i = 0 ; i < members [d ].count ; i ++ ) {
@@ -1626,7 +1635,7 @@ static void k8s_ids_sort_unique(k8s_ids_t *v) {
16261635 if (v -> count < PAIR_LEN ) {
16271636 return ;
16281637 }
1629- qsort (v -> items , (size_t )v -> count , sizeof (* v -> items ), k8s_cmp_id );
1638+ k8s_qsort (v -> items , (size_t )v -> count , sizeof (* v -> items ), k8s_cmp_id );
16301639 int w = SKIP_ONE ;
16311640 for (int i = SKIP_ONE ; i < v -> count ; i ++ ) {
16321641 if (v -> items [i ] != v -> items [w - SKIP_ONE ]) {
@@ -1974,7 +1983,7 @@ static void k8s_link_crds(cbm_pipeline_ctx_t *ctx, k8s_bundles_t *b, const k8s_f
19741983 snprintf (order [i ].key , sizeof (order [i ].key ), "%s/%s" , f -> crds [i ].group , f -> crds [i ].kind );
19751984 order [i ].crd = i ;
19761985 }
1977- qsort (order , (size_t )f -> crd_n , sizeof (* order ), k8s_cmp_crd_key );
1986+ k8s_qsort (order , (size_t )f -> crd_n , sizeof (* order ), k8s_cmp_crd_key );
19781987 for (int i = f -> crd_n - SKIP_ONE ; i >= 0 ; i -- ) {
19791988 cbm_ht_set (by_type , order [i ].key , (void * )(intptr_t )(i + SKIP_ONE )); /* first of run */
19801989 }
@@ -2128,7 +2137,7 @@ static int k8s_cmp_match(const void *a, const void *b) {
21282137 * there is one, is the one it selects. */
21292138static int k8s_draw_matches (cbm_pipeline_ctx_t * ctx , const k8s_record_array_t * recs ,
21302139 const k8s_record_t * svc , k8s_match_t * m , int n ) {
2131- qsort (m , (size_t )n , sizeof (* m ), k8s_cmp_match );
2140+ k8s_qsort (m , (size_t )n , sizeof (* m ), k8s_cmp_match );
21322141 int edges = 0 ;
21332142 for (int g = 0 ; g < n ;) {
21342143 int end = g ;
0 commit comments