Files
git/compat/precompose_utf8.h
T
Ihar Hrachyshka 1eb281159f precompose_utf8: use a flex array for d_name
On macOS, git status may abort while reading a directory entry
whose UTF-8 name grows past NAME_MAX bytes:

  __chk_fail_overflow
  __strlcpy_chk
  precompose_utf8_readdir
  read_directory_recursive
  wt_status_collect
  cmd_status

The precompose wrapper already reallocates dirent_prec_psx for
long names, but d_name is declared as char[NAME_MAX + 1]. A
fortified libc can still see that declared object size and reject a
larger strlcpy bound, even though the allocation was grown.

Make d_name a FLEX_ARRAY and size allocations from offsetof(). That
matches the actual object layout with the dynamic allocation, so the
fortified copy sees a destination whose size can grow with max_name_len.

Add a regression test that creates an over-NAME_MAX non-ASCII basename
and runs status with core.precomposeunicode enabled.

Signed-off-by: Ihar Hrachyshka <ihar.hrachyshka@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-04 17:59:36 -07:00

49 lines
1.4 KiB
C

#ifndef PRECOMPOSE_UNICODE_H
#define PRECOMPOSE_UNICODE_H
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <iconv.h>
typedef struct dirent_prec_psx {
ino_t d_ino; /* Posix */
size_t max_name_len; /* See below */
unsigned char d_type; /* available on all systems git runs on */
/*
* See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html
* Start with room for NAME_MAX + 1 bytes, but keep d_name as a
* flexible array. Some systems have NAME_MAX=255 while strlen(d_name)
* from readdir() may return 508 or 510 bytes. Grow the allocation as
* needed in precompose_utf8_readdir().
*/
char d_name[FLEX_ARRAY];
} dirent_prec_psx;
typedef struct {
iconv_t ic_precompose;
DIR *dirp;
struct dirent_prec_psx *dirent_nfc;
} PREC_DIR;
const char *precompose_argv_prefix(int argc, const char **argv, const char *prefix);
const char *precompose_string_if_needed(const char *in);
void probe_utf8_pathname_composition(void);
PREC_DIR *precompose_utf8_opendir(const char *dirname);
struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *dirp);
int precompose_utf8_closedir(PREC_DIR *dirp);
#ifndef PRECOMPOSE_UNICODE_C
#define dirent dirent_prec_psx
#define opendir(n) precompose_utf8_opendir(n)
#define readdir(d) precompose_utf8_readdir(d)
#define closedir(d) precompose_utf8_closedir(d)
#define DIR PREC_DIR
#endif /* PRECOMPOSE_UNICODE_C */
#endif /* PRECOMPOSE_UNICODE_H */