@@ -207,7 +207,6 @@ static char *config_file_strip_comment(char *str)
207207
208208static char * config_file_extract_value (char * line )
209209{
210- char * dst = NULL ;
211210 while (ISSPACE ((int )* line ))
212211 line ++ ;
213212
@@ -255,13 +254,9 @@ static char *config_file_extract_value(char *line)
255254 return strdup (value );
256255 }
257256
258- /* Note 2: This is an unrolled strldup call
259- * to avoid an unnecessary dependency -
260- * call is strldup("", sizeof(""))
261- **/
262- dst = (char * )malloc (sizeof (char ) * 2 );
263- strlcpy (dst , "" , 1 );
264- return dst ;
257+ /* Note 2: Return an empty string.
258+ * calloc gives us a NUL-terminated empty string in one call. */
259+ return (char * )calloc (1 , 1 );
265260}
266261
267262/* Move semantics? */
@@ -271,32 +266,30 @@ static void config_file_add_child_list(config_file_t *parent,
271266 struct config_entry_list * list = child -> entries ;
272267 bool merge_hash_map = false;
273268
274- if (parent -> entries )
269+ /* set list readonly */
270+ while (list )
275271 {
276- struct config_entry_list * head = parent -> entries ;
277- while ( head -> next )
278- head = head -> next ;
272+ list -> readonly = true ;
273+ list = list -> next ;
274+ }
279275
280- /* set list readonly */
281- while (list )
276+ if (parent -> entries )
277+ {
278+ /* Use tracked tail instead of walking the list */
279+ if (parent -> tail )
280+ parent -> tail -> next = child -> entries ;
281+ else
282282 {
283- list -> readonly = true;
284- list = list -> next ;
283+ struct config_entry_list * head = parent -> entries ;
284+ while (head -> next )
285+ head = head -> next ;
286+ head -> next = child -> entries ;
285287 }
286- head -> next = child -> entries ;
287288
288289 merge_hash_map = true;
289290 }
290291 else
291- {
292- /* set list readonly */
293- while (list )
294- {
295- list -> readonly = true;
296- list = list -> next ;
297- }
298292 parent -> entries = child -> entries ;
299- }
300293
301294 /* Rebase tail. */
302295 if (parent -> entries )
@@ -442,12 +435,21 @@ static int config_file_load_internal(
442435
443436 while (!filestream_eof (file ))
444437 {
445- char * line = NULL ;
446- struct config_entry_list * list = (struct config_entry_list * )
447- malloc (sizeof (* list ));
438+ struct config_entry_list * list = NULL ;
439+ char * line = filestream_getline (file );
440+
441+ if (!line )
442+ continue ;
443+
444+ if (string_is_empty (line ))
445+ {
446+ free (line );
447+ continue ;
448+ }
448449
449- if (!list )
450+ if (!( list = ( struct config_entry_list * ) malloc ( sizeof ( * list ))) )
450451 {
452+ free (line );
451453 filestream_close (file );
452454 return -1 ;
453455 }
@@ -457,17 +459,7 @@ static int config_file_load_internal(
457459 list -> value = NULL ;
458460 list -> next = NULL ;
459461
460- line = filestream_getline (file );
461-
462- if (!line )
463- {
464- free (list );
465- continue ;
466- }
467-
468- if (
469- !string_is_empty (line )
470- && config_file_parse_line (conf , list , line , cb ))
462+ if (config_file_parse_line (conf , list , line , cb ))
471463 {
472464 if (conf -> entries )
473465 conf -> tail -> next = list ;
@@ -492,11 +484,10 @@ static int config_file_load_internal(
492484 }
493485 }
494486 }
487+ else
488+ free (list );
495489
496490 free (line );
497-
498- if (list != conf -> tail )
499- free (list );
500491 }
501492
502493 filestream_close (file );
@@ -507,10 +498,8 @@ static int config_file_load_internal(
507498static bool config_file_parse_line (config_file_t * conf ,
508499 struct config_entry_list * list , char * line , config_file_cb_t * cb )
509500{
510- size_t cur_size = 32 ;
511501 size_t idx = 0 ;
512502 char * key = NULL ;
513- char * key_tmp = NULL ;
514503 /* Remove any comment text */
515504 char * comment = config_file_strip_comment (line );
516505
@@ -596,31 +585,23 @@ static bool config_file_parse_line(config_file_t *conf,
596585 while (ISSPACE ((int )* line ))
597586 line ++ ;
598587
599- /* Allocate storage for key */
600- if (!(key = (char * )malloc (cur_size + 1 )))
601- return false;
602-
603- /* Copy line contents into key until we
604- * reach the next space character */
605- while (isgraph ((int )* line ))
588+ /* Measure key length first (up to next non-graph char),
589+ * then copy once - avoids malloc+realloc growth pattern */
606590 {
607- /* If current key storage is too small,
608- * double its size */
609- if (idx == cur_size )
610- {
611- cur_size *= 2 ;
612- if (!(key_tmp = (char * )realloc (key , cur_size + 1 )))
613- {
614- free (key );
615- return false;
616- }
591+ const char * key_start = line ;
592+ while (isgraph ((int )* line ))
593+ line ++ ;
594+ idx = (size_t )(line - key_start );
617595
618- key = key_tmp ;
619- }
596+ if ( idx == 0 )
597+ return false;
620598
621- key [idx ++ ] = * line ++ ;
599+ if (!(key = (char * )malloc (idx + 1 )))
600+ return false;
601+
602+ memcpy (key , key_start , idx );
603+ key [idx ] = '\0' ;
622604 }
623- key [idx ] = '\0' ;
624605
625606 /* Add key and value entries to list */
626607 list -> key = key ;
@@ -670,43 +651,45 @@ static int config_file_from_string_internal(
670651
671652 while (line )
672653 {
673- struct config_entry_list * list = (struct config_entry_list * )
674- malloc (sizeof (* list ));
675-
676- if (!list )
677- return -1 ;
678-
679- list -> readonly = false;
680- list -> key = NULL ;
681- list -> value = NULL ;
682- list -> next = NULL ;
654+ struct config_entry_list * list = NULL ;
683655
684656 /* Parse current line */
685- if (
686- !string_is_empty (line )
687- && config_file_parse_line (conf , list , line , NULL ))
657+ if (!string_is_empty (line ))
688658 {
689- if (conf -> entries )
690- conf -> tail -> next = list ;
691- else
692- conf -> entries = list ;
659+ list = (struct config_entry_list * )
660+ malloc (sizeof (* list ));
693661
694- conf -> tail = list ;
662+ if (!list )
663+ return -1 ;
695664
696- if (list -> key )
665+ list -> readonly = false;
666+ list -> key = NULL ;
667+ list -> value = NULL ;
668+ list -> next = NULL ;
669+
670+ if (config_file_parse_line (conf , list , line , NULL ))
697671 {
698- /* Only add entry to the map if an entry
699- * with the specified value does not
700- * already exist */
701- uint32_t hash = rhmap_hash_string (list -> key );
702- if (!RHMAP_HAS_FULL (conf -> entries_map , hash , list -> key ))
703- RHMAP_SET_FULL (conf -> entries_map , hash , list -> key , list );
672+ if (conf -> entries )
673+ conf -> tail -> next = list ;
674+ else
675+ conf -> entries = list ;
676+
677+ conf -> tail = list ;
678+
679+ if (list -> key )
680+ {
681+ /* Only add entry to the map if an entry
682+ * with the specified value does not
683+ * already exist */
684+ uint32_t hash = rhmap_hash_string (list -> key );
685+ if (!RHMAP_HAS_FULL (conf -> entries_map , hash , list -> key ))
686+ RHMAP_SET_FULL (conf -> entries_map , hash , list -> key , list );
687+ }
704688 }
689+ else
690+ free (list );
705691 }
706692
707- if (list != conf -> tail )
708- free (list );
709-
710693 /* Get next line of config file */
711694 line = strtok_r (NULL , "\n" , & save_ptr );
712695 }
@@ -1409,20 +1392,17 @@ bool config_file_write(config_file_t *conf, const char *path, bool sort)
14091392 config_file_dump (conf , stdout , sort );
14101393 else
14111394 {
1412- void * buf = NULL ;
1395+ char buf [ 0x4000 ] ;
14131396 FILE * file = (FILE * )fopen_utf8 (path , "wb" );
14141397 if (!file )
14151398 return false;
14161399
1417- buf = calloc (1 , 0x4000 );
1418- setvbuf (file , (char * )buf , _IOFBF , 0x4000 );
1400+ setvbuf (file , buf , _IOFBF , sizeof (buf ));
14191401
14201402 config_file_dump (conf , file , sort );
14211403
14221404 if (file != stdout )
14231405 fclose (file );
1424- if (buf )
1425- free (buf );
14261406
14271407 /* Only update modified flag if config file
14281408 * is actually written to disk */
0 commit comments