Skip to content

Commit 6fb5043

Browse files
committed
file.c: Stop passing NULL for encoding
`rb_encoding *` is defined as `nonnull` so `if (enc)` is optimized out by the compiler. We have to pass a boolean alongside it to avoid crashes.
1 parent 2d10f15 commit 6fb5043

1 file changed

Lines changed: 65 additions & 59 deletions

File tree

file.c

Lines changed: 65 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3571,8 +3571,8 @@ static const char file_alt_separator[] = {FILE_ALT_SEPARATOR, '\0'};
35713571
# define isADS(x) 0
35723572
#endif
35733573

3574-
#define Next(p, e, enc) ((p) + ((enc) ? rb_enc_mbclen((p), (e), (enc)) : 1))
3575-
#define Inc(p, e, enc) ((p) = Next((p), (e), (enc)))
3574+
#define Next(p, e, mb_enc, enc) ((p) + ((mb_enc) ? rb_enc_mbclen((p), (e), (enc)) : 1))
3575+
#define Inc(p, e, mb_enc, enc) ((p) = Next((p), (e), (mb_enc), (enc)))
35763576

35773577
#if defined(DOSISH_UNC)
35783578
#define has_unc(buf) (isdirsep((buf)[0]) && isdirsep((buf)[1]))
@@ -3645,31 +3645,37 @@ skiproot(const char *path, const char *end)
36453645
return (char *)path;
36463646
}
36473647

3648-
#define nextdirsep rb_enc_path_next
3649-
char *
3650-
rb_enc_path_next(const char *s, const char *e, rb_encoding *enc)
3648+
static inline char *
3649+
enc_path_next(const char *s, const char *e, bool mb_enc, rb_encoding *enc)
36513650
{
36523651
while (s < e && !isdirsep(*s)) {
3653-
Inc(s, e, enc);
3652+
Inc(s, e, mb_enc, enc);
36543653
}
36553654
return (char *)s;
36563655
}
36573656

3657+
#define nextdirsep rb_enc_path_next
3658+
char *
3659+
rb_enc_path_next(const char *s, const char *e, rb_encoding *enc)
3660+
{
3661+
return enc_path_next(s, e, true, enc);
3662+
}
3663+
36583664
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
3659-
#define skipprefix rb_enc_path_skip_prefix
3665+
#define skipprefix enc_path_skip_prefix
36603666
#else
3661-
#define skipprefix(path, end, enc) (path)
3667+
#define skipprefix(path, end, mb_enc, enc) (path)
36623668
#endif
3663-
char *
3664-
rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
3669+
static inline char *
3670+
enc_path_skip_prefix(const char *path, const char *end, bool mb_enc, rb_encoding *enc)
36653671
{
36663672
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
36673673
#ifdef DOSISH_UNC
36683674
if (path + 2 <= end && isdirsep(path[0]) && isdirsep(path[1])) {
36693675
path += 2;
36703676
while (path < end && isdirsep(*path)) path++;
3671-
if ((path = rb_enc_path_next(path, end, enc)) < end && path[0] && path[1] && !isdirsep(path[1]))
3672-
path = rb_enc_path_next(path + 1, end, enc);
3677+
if ((path = enc_path_next(path, end, mb_enc, enc)) < end && path[0] && path[1] && !isdirsep(path[1]))
3678+
path = enc_path_next(path + 1, end, mb_enc, enc);
36733679
return (char *)path;
36743680
}
36753681
#endif
@@ -3681,11 +3687,17 @@ rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
36813687
return (char *)path;
36823688
}
36833689

3690+
char *
3691+
rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
3692+
{
3693+
return enc_path_skip_prefix(path, end, true, enc);
3694+
}
3695+
36843696
static inline char *
36853697
skipprefixroot(const char *path, const char *end, rb_encoding *enc)
36863698
{
36873699
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER)
3688-
char *p = skipprefix(path, end, enc);
3700+
char *p = skipprefix(path, end, true, enc);
36893701
while (isdirsep(*p)) p++;
36903702
return p;
36913703
#else
@@ -3705,34 +3717,35 @@ rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc)
37053717
last = (char *)tmp;
37063718
}
37073719
else {
3708-
Inc(path, end, enc);
3720+
Inc(path, end, true, enc);
37093721
}
37103722
}
37113723
return last;
37123724
}
37133725

37143726
static inline char *
3715-
strrdirsep(const char *path, const char *end, rb_encoding *enc)
3727+
strrdirsep(const char *path, const char *end, bool mb_enc, rb_encoding *enc)
37163728
{
3717-
if (RB_LIKELY(enc == NULL)) {
3718-
const char *cursor = end - 1;
3729+
if (RB_UNLIKELY(mb_enc)) {
3730+
return rb_enc_path_last_separator(path, end, enc);
3731+
}
37193732

3720-
while (isdirsep(cursor[0])) {
3721-
cursor--;
3722-
}
3733+
const char *cursor = end - 1;
37233734

3724-
while (cursor >= path) {
3725-
if (isdirsep(cursor[0])) {
3726-
while (cursor > path && isdirsep(cursor[-1])) {
3727-
cursor--;
3728-
}
3729-
return (char *)cursor;
3735+
while (isdirsep(cursor[0])) {
3736+
cursor--;
3737+
}
3738+
3739+
while (cursor >= path) {
3740+
if (isdirsep(cursor[0])) {
3741+
while (cursor > path && isdirsep(cursor[-1])) {
3742+
cursor--;
37303743
}
3731-
cursor--;
3744+
return (char *)cursor;
37323745
}
3733-
return NULL;
3746+
cursor--;
37343747
}
3735-
return rb_enc_path_last_separator(path, end, enc);
3748+
return NULL;
37363749
}
37373750

37383751
static char *
@@ -3745,7 +3758,7 @@ chompdirsep(const char *path, const char *end, rb_encoding *enc)
37453758
if (path >= end) return (char *)last;
37463759
}
37473760
else {
3748-
Inc(path, end, enc);
3761+
Inc(path, end, true, enc);
37493762
}
37503763
}
37513764
return (char *)path;
@@ -3790,7 +3803,7 @@ ntfs_tail(const char *path, const char *end, rb_encoding *enc)
37903803
if (isADS(*path)) path++;
37913804
}
37923805
else {
3793-
Inc(path, end, enc);
3806+
Inc(path, end, true, enc);
37943807
}
37953808
}
37963809
return (char *)path;
@@ -3852,7 +3865,7 @@ copy_home_path(VALUE result, const char *dir)
38523865
rb_enc_associate_index(result, encidx);
38533866
#if defined DOSISH || defined __CYGWIN__
38543867
enc = rb_enc_from_index(encidx);
3855-
for (bend = (p = buf) + dirlen; p < bend; Inc(p, bend, enc)) {
3868+
for (bend = (p = buf) + dirlen; p < bend; Inc(p, bend, true, enc)) {
38563869
if (*p == '\\') {
38573870
*p = '/';
38583871
}
@@ -4096,7 +4109,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
40964109
if (isdirsep(*s)) {
40974110
/* specified full path, but not drive letter nor UNC */
40984111
/* we need to get the drive letter or UNC share name */
4099-
p = skipprefix(buf, p, enc);
4112+
p = skipprefix(buf, p, true, enc);
41004113
}
41014114
else
41024115
#endif /* defined DOSISH || defined __CYGWIN__ */
@@ -4124,7 +4137,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
41244137
rb_str_set_len(result, p-buf+1);
41254138
BUFCHECK(bdiff + 1 >= buflen);
41264139
p[1] = 0;
4127-
root = skipprefix(buf, p+1, enc);
4140+
root = skipprefix(buf, p+1, true, enc);
41284141

41294142
b = s;
41304143
while (*s) {
@@ -4140,7 +4153,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
41404153
/* We must go back to the parent */
41414154
char *n;
41424155
*p = '\0';
4143-
if (!(n = strrdirsep(root, p, enc))) {
4156+
if (!(n = strrdirsep(root, p, true, enc))) {
41444157
*p = '/';
41454158
}
41464159
else {
@@ -4203,7 +4216,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
42034216
}
42044217
}
42054218
#endif /* __APPLE__ */
4206-
Inc(s, fend, enc);
4219+
Inc(s, fend, true, enc);
42074220
break;
42084221
}
42094222
}
@@ -4503,7 +4516,7 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE f
45034516
if (*prefixlenp < RSTRING_LEN(*resolvedp)) {
45044517
const char *resolved_str = RSTRING_PTR(*resolvedp);
45054518
const char *resolved_names = resolved_str + *prefixlenp;
4506-
const char *lastsep = strrdirsep(resolved_names, resolved_str + RSTRING_LEN(*resolvedp), enc);
4519+
const char *lastsep = strrdirsep(resolved_names, resolved_str + RSTRING_LEN(*resolvedp), true, enc);
45074520
long len = lastsep ? lastsep - resolved_names : 0;
45084521
rb_str_resize(*resolvedp, *prefixlenp + len);
45094522
}
@@ -4653,7 +4666,7 @@ rb_check_realpath_emulate(VALUE basedir, VALUE path, rb_encoding *origenc, enum
46534666
if (*prefixptr == FILE_ALT_SEPARATOR) {
46544667
*prefixptr = '/';
46554668
}
4656-
Inc(prefixptr, pend, enc);
4669+
Inc(prefixptr, pend, true, enc);
46574670
}
46584671
#endif
46594672

@@ -4907,7 +4920,7 @@ ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encodin
49074920
long f = 0, n = -1;
49084921

49094922
end = name + (alllen ? (size_t)*alllen : strlen(name));
4910-
name = skipprefix(name, end, enc);
4923+
name = skipprefix(name, end, true, enc);
49114924
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
49124925
root = name;
49134926
#endif
@@ -4934,7 +4947,7 @@ ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encodin
49344947
#endif /* defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC */
49354948
}
49364949
else {
4937-
if (!(p = strrdirsep(name, end, enc))) {
4950+
if (!(p = strrdirsep(name, end, true, enc))) {
49384951
p = name;
49394952
}
49404953
else {
@@ -4946,7 +4959,7 @@ ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encodin
49464959
n = chompdirsep(p, end, enc) - p;
49474960
#endif
49484961
for (q = p; q - p < n && *q == '.'; q++);
4949-
for (e = 0; q - p < n; Inc(q, end, enc)) {
4962+
for (e = 0; q - p < n; Inc(q, end, true, enc)) {
49504963
if (*q == '.') e = q;
49514964
}
49524965
if (e) f = e - p;
@@ -5059,30 +5072,23 @@ rb_file_dirname(VALUE fname)
50595072
return rb_file_dirname_n(fname, 1);
50605073
}
50615074

5062-
static inline rb_encoding *
5063-
path_enc_get(VALUE str)
5064-
{
5065-
if (RB_LIKELY(rb_str_enc_fastpath(str))) {
5066-
return NULL;
5067-
}
5068-
return rb_str_enc_get(str);
5069-
}
5070-
50715075
static VALUE
50725076
rb_file_dirname_n(VALUE fname, int n)
50735077
{
50745078
const char *name, *root, *p, *end;
50755079
VALUE dirname;
5076-
rb_encoding *enc;
50775080

50785081
if (n < 0) rb_raise(rb_eArgError, "negative level: %d", n);
50795082
CheckPath(fname, name);
50805083
end = name + RSTRING_LEN(fname);
5081-
enc = path_enc_get(fname);
5084+
5085+
bool mb_enc = !rb_str_enc_fastpath(fname);
5086+
rb_encoding *enc = rb_str_enc_get(fname);
5087+
50825088
root = skiproot(name, end);
50835089
#ifdef DOSISH_UNC
50845090
if (root > name + 1 && isdirsep(*name))
5085-
root = skipprefix(name = root - 2, end, enc);
5091+
root = skipprefix(name = root - 2, end, mb_enc, enc);
50865092
#else
50875093
if (root > name + 1)
50885094
name = root - 1;
@@ -5093,7 +5099,7 @@ rb_file_dirname_n(VALUE fname, int n)
50935099
else {
50945100
p = end;
50955101
while (n) {
5096-
if (!(p = strrdirsep(root, p, enc))) {
5102+
if (!(p = strrdirsep(root, p, mb_enc, enc))) {
50975103
p = root;
50985104
break;
50995105
}
@@ -5102,17 +5108,17 @@ rb_file_dirname_n(VALUE fname, int n)
51025108
}
51035109

51045110
if (p == name) {
5105-
return rb_enc_str_new(".", 1, rb_str_enc_get(fname));
5111+
return rb_enc_str_new(".", 1, enc);
51065112
}
51075113
#ifdef DOSISH_DRIVE_LETTER
51085114
if (has_drive_letter(name) && isdirsep(*(name + 2))) {
51095115
const char *top = skiproot(name + 2, end);
5110-
dirname = rb_enc_str_new(name, 3, rb_str_enc_get(fname));
5116+
dirname = rb_enc_str_new(name, 3, enc);
51115117
rb_str_cat(dirname, top, p - top);
51125118
}
51135119
else
51145120
#endif
5115-
dirname = rb_enc_str_new(name, p - name, rb_str_enc_get(fname));
5121+
dirname = rb_enc_str_new(name, p - name, enc);
51165122
#ifdef DOSISH_DRIVE_LETTER
51175123
if (has_drive_letter(name) && root == name + 2 && p - name == 2)
51185124
rb_str_cat(dirname, ".", 1);
@@ -5137,7 +5143,7 @@ ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
51375143
{
51385144
const char *p, *e, *end = name + (len ? *len : (long)strlen(name));
51395145

5140-
p = strrdirsep(name, end, enc); /* get the last path component */
5146+
p = strrdirsep(name, end, true, enc); /* get the last path component */
51415147
if (!p)
51425148
p = name;
51435149
else
@@ -5170,7 +5176,7 @@ ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
51705176
#endif
51715177
else if (isdirsep(*p))
51725178
break;
5173-
Inc(p, end, enc);
5179+
Inc(p, end, true, enc);
51745180
}
51755181

51765182
if (len) {

0 commit comments

Comments
 (0)