1diff -u libmagic.orig/apprentice.c libmagic/apprentice.c 2--- libmagic.orig/apprentice.c 2022-09-13 20:46:07.000000000 +0200 3+++ libmagic/apprentice.c 2023-10-25 17:56:17.066628832 +0200 4@@ -48,7 +48,9 @@ 5 #ifdef QUICK 6 #include <sys/mman.h> 7 #endif 8+#ifdef HAVE_DIRENT_H 9 #include <dirent.h> 10+#endif 11 #include <limits.h> 12 #ifdef HAVE_BYTESWAP_H 13 #include <byteswap.h> 14@@ -147,10 +149,7 @@ 15 #endif 16 17 private char *mkdbname(struct magic_set *, const char *, int); 18-private struct magic_map *apprentice_buf(struct magic_set *, struct magic *, 19- size_t); 20 private struct magic_map *apprentice_map(struct magic_set *, const char *); 21-private int check_buffer(struct magic_set *, struct magic_map *, const char *); 22 private void apprentice_unmap(struct magic_map *); 23 private int apprentice_compile(struct magic_set *, struct magic_map *, 24 const char *); 25@@ -186,6 +185,8 @@ 26 { NULL, 0, NULL } 27 }; 28 29+#include "../data_file.c" 30+ 31 #ifdef COMPILE_ONLY 32 33 int main(int, char *[]); 34@@ -446,21 +447,13 @@ 35 struct mlist *ml; 36 37 mlp->map = NULL; 38- if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) 39+ if ((ml = CAST(struct mlist *, emalloc(sizeof(*ml)))) == NULL) 40 return -1; 41 42 ml->map = idx == 0 ? map : NULL; 43 ml->magic = map->magic[idx]; 44 ml->nmagic = map->nmagic[idx]; 45- if (ml->nmagic) { 46- ml->magic_rxcomp = CAST(file_regex_t **, 47- calloc(ml->nmagic, sizeof(*ml->magic_rxcomp))); 48- if (ml->magic_rxcomp == NULL) { 49- free(ml); 50- return -1; 51- } 52- } else 53- ml->magic_rxcomp = NULL; 54+ 55 mlp->prev->next = ml; 56 ml->prev = mlp->prev; 57 ml->next = mlp; 58@@ -539,13 +532,19 @@ 59 return; 60 for (i = 0; i < MAGIC_SETS; i++) 61 mlist_free(ms->mlist[i]); 62- free(ms->o.pbuf); 63- free(ms->o.buf); 64- free(ms->c.li); 65+ if (ms->o.pbuf) { 66+ efree(ms->o.pbuf); 67+ } 68+ if (ms->o.buf) { 69+ efree(ms->o.buf); 70+ } 71+ if (ms->c.li) { 72+ efree(ms->c.li); 73+ } 74 #ifdef USE_C_LOCALE 75 freelocale(ms->c_lc_ctype); 76 #endif 77- free(ms); 78+ efree(ms); 79 } 80 81 protected struct magic_set * 82@@ -554,7 +553,7 @@ 83 struct magic_set *ms; 84 size_t i, len; 85 86- if ((ms = CAST(struct magic_set *, calloc(CAST(size_t, 1u), 87+ if ((ms = CAST(struct magic_set *, ecalloc(CAST(size_t, 1u), 88 sizeof(struct magic_set)))) == NULL) 89 return NULL; 90 91@@ -567,7 +566,7 @@ 92 ms->o.blen = 0; 93 len = (ms->c.len = 10) * sizeof(*ms->c.li); 94 95- if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) 96+ if ((ms->c.li = CAST(struct level_info *, emalloc(len))) == NULL) 97 goto free; 98 99 ms->event_flags = 0; 100@@ -597,42 +596,28 @@ 101 private void 102 apprentice_unmap(struct magic_map *map) 103 { 104- size_t i; 105- char *p; 106 if (map == NULL) 107 return; 108- 109- switch (map->type) { 110- case MAP_TYPE_USER: 111- break; 112- case MAP_TYPE_MALLOC: 113- p = CAST(char *, map->p); 114- for (i = 0; i < MAGIC_SETS; i++) { 115- char *b = RCAST(char *, map->magic[i]); 116- if (p != NULL && b >= p && b <= p + map->len) 117- continue; 118- free(b); 119+ if (map->p != php_magic_database) { 120+ if (map->p == NULL) { 121+ int j; 122+ for (j = 0; j < MAGIC_SETS; j++) { 123+ if (map->magic[j]) { 124+ efree(map->magic[j]); 125+ } 126+ } 127+ } else { 128+ efree(map->p); 129 } 130- free(p); 131- break; 132-#ifdef QUICK 133- case MAP_TYPE_MMAP: 134- if (map->p && map->p != MAP_FAILED) 135- (void)munmap(map->p, map->len); 136- break; 137-#endif 138- default: 139- fprintf(stderr, "Bad map type %d", map->type); 140- abort(); 141 } 142- free(map); 143+ efree(map); 144 } 145 146 private struct mlist * 147 mlist_alloc(void) 148 { 149 struct mlist *mlist; 150- if ((mlist = CAST(struct mlist *, calloc(1, sizeof(*mlist)))) == NULL) { 151+ if ((mlist = CAST(struct mlist *, ecalloc(1, sizeof(*mlist)))) == NULL) { 152 return NULL; 153 } 154 mlist->next = mlist->prev = mlist; 155@@ -653,21 +638,9 @@ 156 private void 157 mlist_free_one(struct mlist *ml) 158 { 159- size_t i; 160- 161 if (ml->map) 162 apprentice_unmap(CAST(struct magic_map *, ml->map)); 163- 164- for (i = 0; i < ml->nmagic; ++i) { 165- if (ml->magic_rxcomp[i]) { 166- file_regfree(ml->magic_rxcomp[i]); 167- free(ml->magic_rxcomp[i]); 168- ml->magic_rxcomp[i] = NULL; 169- } 170- } 171- free(ml->magic_rxcomp); 172- ml->magic_rxcomp = NULL; 173- free(ml); 174+ efree(ml); 175 } 176 177 private void 178@@ -686,51 +659,6 @@ 179 mlist_free_one(mlist); 180 } 181 182-#ifndef COMPILE_ONLY 183-/* void **bufs: an array of compiled magic files */ 184-protected int 185-buffer_apprentice(struct magic_set *ms, struct magic **bufs, 186- size_t *sizes, size_t nbufs) 187-{ 188- size_t i, j; 189- struct mlist *ml; 190- struct magic_map *map; 191- 192- if (nbufs == 0) 193- return -1; 194- 195- (void)file_reset(ms, 0); 196- 197- init_file_tables(); 198- 199- for (i = 0; i < MAGIC_SETS; i++) { 200- mlist_free(ms->mlist[i]); 201- if ((ms->mlist[i] = mlist_alloc()) == NULL) { 202- file_oomem(ms, sizeof(*ms->mlist[i])); 203- goto fail; 204- } 205- } 206- 207- for (i = 0; i < nbufs; i++) { 208- map = apprentice_buf(ms, bufs[i], sizes[i]); 209- if (map == NULL) 210- goto fail; 211- 212- for (j = 0; j < MAGIC_SETS; j++) { 213- if (add_mlist(ms->mlist[j], map, j) == -1) { 214- file_oomem(ms, sizeof(*ml)); 215- goto fail; 216- } 217- } 218- } 219- 220- return 0; 221-fail: 222- mlist_free_all(ms); 223- return -1; 224-} 225-#endif 226- 227 /* const char *fn: list of magic files and directories */ 228 protected int 229 file_apprentice(struct magic_set *ms, const char *fn, int action) 230@@ -741,12 +669,28 @@ 231 232 (void)file_reset(ms, 0); 233 234+/* XXX disabling default magic loading so the compiled in data is used */ 235+#if 0 236 if ((fn = magic_getpath(fn, action)) == NULL) 237 return -1; 238+#endif 239 240 init_file_tables(); 241 242- if ((mfn = strdup(fn)) == NULL) { 243+ if (fn == NULL) 244+ fn = getenv("MAGIC"); 245+ if (fn == NULL) { 246+ for (i = 0; i < MAGIC_SETS; i++) { 247+ mlist_free(ms->mlist[i]); 248+ if ((ms->mlist[i] = mlist_alloc()) == NULL) { 249+ file_oomem(ms, sizeof(*ms->mlist[i])); 250+ return -1; 251+ } 252+ } 253+ return apprentice_1(ms, fn, action); 254+ } 255+ 256+ if ((mfn = estrdup(fn)) == NULL) { 257 file_oomem(ms, strlen(fn)); 258 return -1; 259 } 260@@ -759,7 +703,7 @@ 261 mlist_free(ms->mlist[j]); 262 ms->mlist[j] = NULL; 263 } 264- free(mfn); 265+ efree(mfn); 266 return -1; 267 } 268 } 269@@ -776,7 +720,7 @@ 270 fn = p; 271 } 272 273- free(mfn); 274+ efree(mfn); 275 276 if (errs == -1) { 277 for (i = 0; i < MAGIC_SETS; i++) { 278@@ -1289,7 +1233,7 @@ 279 280 size_t incr = mset[i].max + ALLOC_INCR; 281 if ((mp = CAST(struct magic_entry *, 282- realloc(mset[i].me, sizeof(*mp) * incr))) == 283+ erealloc(mset[i].me, sizeof(*mp) * incr))) == 284 NULL) { 285 file_oomem(ms, sizeof(*mp) * incr); 286 return -1; 287@@ -1312,13 +1256,19 @@ 288 load_1(struct magic_set *ms, int action, const char *fn, int *errs, 289 struct magic_entry_set *mset) 290 { 291- size_t lineno = 0, llen = 0; 292+ char buffer[BUFSIZ + 1]; 293 char *line = NULL; 294- ssize_t len; 295+ size_t len; 296+ size_t lineno = 0; 297 struct magic_entry me; 298 299- FILE *f = fopen(ms->file = fn, "r"); 300- if (f == NULL) { 301+ php_stream *stream; 302+ 303+ 304+ ms->file = fn; 305+ stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL); 306+ 307+ if (stream == NULL) { 308 if (errno != ENOENT) 309 file_error(ms, errno, "cannot read magic file `%s'", 310 fn); 311@@ -1328,8 +1278,7 @@ 312 313 memset(&me, 0, sizeof(me)); 314 /* read and parse this file */ 315- for (ms->line = 1; (len = getline(&line, &llen, f)) != -1; 316- ms->line++) { 317+ for (ms->line = 1; (line = php_stream_get_line(stream, buffer , BUFSIZ, &len)) != NULL; ms->line++) { 318 if (len == 0) /* null line, garbage, etc */ 319 continue; 320 if (line[len - 1] == '\n') { 321@@ -1388,8 +1337,8 @@ 322 } 323 if (me.mp) 324 (void)addentry(ms, &me, mset); 325- free(line); 326- (void)fclose(f); 327+ efree(line); 328+ php_stream_close(stream); 329 } 330 331 /* 332@@ -1474,7 +1423,7 @@ 333 } 334 335 slen = sizeof(**ma) * mentrycount; 336- if ((*ma = CAST(struct magic *, malloc(slen))) == NULL) { 337+ if ((*ma = CAST(struct magic *, emalloc(slen))) == NULL) { 338 file_oomem(ms, slen); 339 return -1; 340 } 341@@ -1496,8 +1445,8 @@ 342 if (me == NULL) 343 return; 344 for (i = 0; i < nme; i++) 345- free(me[i].mp); 346- free(me); 347+ efree(me[i].mp); 348+ efree(me); 349 } 350 351 private struct magic_map * 352@@ -1506,18 +1455,19 @@ 353 int errs = 0; 354 uint32_t i, j; 355 size_t files = 0, maxfiles = 0; 356- char **filearr = NULL, *mfn; 357- struct stat st; 358+ char **filearr = NULL; 359+ zend_stat_t st = {0}; 360 struct magic_map *map; 361 struct magic_entry_set mset[MAGIC_SETS]; 362- DIR *dir; 363- struct dirent *d; 364+ php_stream *dir; 365+ php_stream_dirent d; 366+ 367 368 memset(mset, 0, sizeof(mset)); 369 ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ 370 371 372- if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) 373+ if ((map = CAST(struct magic_map *, ecalloc(1, sizeof(*map)))) == NULL) 374 { 375 file_oomem(ms, sizeof(*map)); 376 return NULL; 377@@ -1529,52 +1479,50 @@ 378 (void)fprintf(stderr, "%s\n", usg_hdr); 379 380 /* load directory or file */ 381- if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { 382- dir = opendir(fn); 383+ /* FIXME: Read file names and sort them to prevent 384+ non-determinism. See Debian bug #488562. */ 385+ if (php_sys_stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { 386+ int mflen; 387+ char mfn[MAXPATHLEN]; 388+ 389+ dir = php_stream_opendir((char *)fn, REPORT_ERRORS, NULL); 390 if (!dir) { 391 errs++; 392 goto out; 393 } 394- while ((d = readdir(dir)) != NULL) { 395- if (d->d_name[0] == '.') 396- continue; 397- if (asprintf(&mfn, "%s/%s", fn, d->d_name) < 0) { 398+ while (php_stream_readdir(dir, &d)) { 399+ if ((mflen = snprintf(mfn, sizeof(mfn), "%s/%s", fn, d.d_name)) < 0) { 400 file_oomem(ms, 401- strlen(fn) + strlen(d->d_name) + 2); 402+ strlen(fn) + strlen(d.d_name) + 2); 403 errs++; 404- closedir(dir); 405+ php_stream_closedir(dir); 406 goto out; 407 } 408- if (stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) { 409- free(mfn); 410+ if (zend_stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) { 411 continue; 412 } 413 if (files >= maxfiles) { 414 size_t mlen; 415- char **nfilearr; 416 maxfiles = (maxfiles + 1) * 2; 417 mlen = maxfiles * sizeof(*filearr); 418- if ((nfilearr = CAST(char **, 419- realloc(filearr, mlen))) == NULL) { 420+ if ((filearr = CAST(char **, 421+ erealloc(filearr, mlen))) == NULL) { 422 file_oomem(ms, mlen); 423- free(mfn); 424- closedir(dir); 425+ php_stream_closedir(dir); 426 errs++; 427 goto out; 428 } 429- filearr = nfilearr; 430 } 431- filearr[files++] = mfn; 432+ filearr[files++] = estrndup(mfn, (mflen > sizeof(mfn) - 1)? sizeof(mfn) - 1: mflen); 433 } 434- closedir(dir); 435+ php_stream_closedir(dir); 436 if (filearr) { 437 qsort(filearr, files, sizeof(*filearr), cmpstrp); 438 for (i = 0; i < files; i++) { 439 load_1(ms, action, filearr[i], &errs, mset); 440- free(filearr[i]); 441+ efree(filearr[i]); 442 } 443- free(filearr); 444- filearr = NULL; 445+ efree(filearr); 446 } 447 } else 448 load_1(ms, action, fn, &errs, mset); 449@@ -1612,7 +1560,6 @@ 450 } 451 452 out: 453- free(filearr); 454 for (j = 0; j < MAGIC_SETS; j++) 455 magic_entry_free(mset[j].me, mset[j].count); 456 457@@ -2060,7 +2007,7 @@ 458 if (me->cont_count == me->max_count) { 459 struct magic *nm; 460 size_t cnt = me->max_count + ALLOC_CHUNK; 461- if ((nm = CAST(struct magic *, realloc(me->mp, 462+ if ((nm = CAST(struct magic *, erealloc(me->mp, 463 sizeof(*nm) * cnt))) == NULL) { 464 file_oomem(ms, sizeof(*nm) * cnt); 465 return -1; 466@@ -2075,7 +2022,7 @@ 467 static const size_t len = sizeof(*m) * ALLOC_CHUNK; 468 if (me->mp != NULL) 469 return 1; 470- if ((m = CAST(struct magic *, malloc(len))) == NULL) { 471+ if ((m = CAST(struct magic *, emalloc(len))) == NULL) { 472 file_oomem(ms, len); 473 return -1; 474 } 475@@ -2301,7 +2248,7 @@ 476 477 m->mask_op = 0; 478 if (*l == '~') { 479- if (!IS_STRING(m->type)) 480+ if (!IS_LIBMAGIC_STRING(m->type)) 481 m->mask_op |= FILE_OPINVERSE; 482 else if (ms->flags & MAGIC_CHECK) 483 file_magwarn(ms, "'~' invalid for string types"); 484@@ -2310,7 +2257,7 @@ 485 m->str_range = 0; 486 m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0; 487 if ((op = get_op(*l)) != -1) { 488- if (IS_STRING(m->type)) { 489+ if (IS_LIBMAGIC_STRING(m->type)) { 490 int r; 491 492 if (op != FILE_OPDIVIDE) { 493@@ -2493,8 +2440,7 @@ 494 495 private int 496 parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line, 497- size_t llen, off_t off, size_t len, const char *name, const char *extra, 498- int nt) 499+ size_t llen, zend_off_t off, size_t len, const char *name, const char *extra, int nt) 500 { 501 size_t i; 502 const char *l = line; 503@@ -2852,13 +2798,19 @@ 504 return -1; 505 } 506 if (m->type == FILE_REGEX) { 507- file_regex_t rx; 508- int rc = file_regcomp(ms, &rx, m->value.s, 509- REG_EXTENDED); 510- if (rc == 0) { 511- file_regfree(&rx); 512+ zend_string *pattern; 513+ int options = 0; 514+ pcre_cache_entry *pce; 515+ 516+ pattern = convert_libmagic_pattern(m->value.s, strlen(m->value.s), options); 517+ 518+ if ((pce = pcre_get_compiled_regex_cache(pattern)) == NULL) { 519+ zend_string_release(pattern); 520+ return -1; 521 } 522- return rc ? -1 : 0; 523+ zend_string_release(pattern); 524+ 525+ return 0; 526 } 527 return 0; 528 default: 529@@ -3230,120 +3182,83 @@ 530 } 531 532 /* 533- * handle a buffer containing a compiled file. 534- */ 535-private struct magic_map * 536-apprentice_buf(struct magic_set *ms, struct magic *buf, size_t len) 537-{ 538- struct magic_map *map; 539- 540- if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 541- file_oomem(ms, sizeof(*map)); 542- return NULL; 543- } 544- map->len = len; 545- map->p = buf; 546- map->type = MAP_TYPE_USER; 547- if (check_buffer(ms, map, "buffer") != 0) { 548- apprentice_unmap(map); 549- return NULL; 550- } 551- return map; 552-} 553- 554-/* 555 * handle a compiled file. 556 */ 557 558 private struct magic_map * 559 apprentice_map(struct magic_set *ms, const char *fn) 560 { 561- int fd; 562- struct stat st; 563+ uint32_t *ptr; 564+ uint32_t version, entries = 0, nentries; 565+ int needsbyteswap; 566 char *dbname = NULL; 567 struct magic_map *map; 568- struct magic_map *rv = NULL; 569+ size_t i; 570+ php_stream *stream = NULL; 571+ php_stream_statbuf st; 572+ 573+ 574 575- fd = -1; 576- if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 577+ if ((map = CAST(struct magic_map *, ecalloc(1, sizeof(*map)))) == NULL) { 578 file_oomem(ms, sizeof(*map)); 579- goto error; 580+ return NULL; 581 } 582- map->type = MAP_TYPE_USER; /* unspecified */ 583+ 584+ if (fn == NULL) { 585+ map->p = (void *)&php_magic_database; 586+ goto internal_loaded; 587+ } 588+ 589+#ifdef PHP_WIN32 590+ /* Don't bother on windows with php_stream_open_wrapper, 591+ return to give apprentice_load() a chance. */ 592+ if (php_stream_stat_path_ex((char *)fn, 0, &st, NULL) == SUCCESS) { 593+ if (st.sb.st_mode & S_IFDIR) { 594+ goto error; 595+ } 596+ } 597+#endif 598 599 dbname = mkdbname(ms, fn, 0); 600 if (dbname == NULL) 601 goto error; 602 603- if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1) 604+ stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL); 605+ 606+ if (!stream) { 607 goto error; 608+ } 609 610- if (fstat(fd, &st) == -1) { 611+#ifndef PHP_WIN32 612+ if (php_stream_stat(stream, &st) < 0) { 613 file_error(ms, errno, "cannot stat `%s'", dbname); 614 goto error; 615 } 616- if (st.st_size < 8 || st.st_size > maxoff_t()) { 617+#endif 618+ if (st.sb.st_size < 8 || st.sb.st_size > maxoff_t()) { 619 file_error(ms, 0, "file `%s' is too %s", dbname, 620- st.st_size < 8 ? "small" : "large"); 621+ st.sb.st_size < 8 ? "small" : "large"); 622 goto error; 623 } 624 625- map->len = CAST(size_t, st.st_size); 626-#ifdef QUICK 627- map->type = MAP_TYPE_MMAP; 628- if ((map->p = mmap(0, CAST(size_t, st.st_size), PROT_READ|PROT_WRITE, 629- MAP_PRIVATE|MAP_FILE, fd, CAST(off_t, 0))) == MAP_FAILED) { 630- file_error(ms, errno, "cannot map `%s'", dbname); 631- goto error; 632- } 633-#else 634 map->type = MAP_TYPE_MALLOC; 635- if ((map->p = CAST(void *, malloc(map->len))) == NULL) { 636- file_oomem(ms, map->len); 637- goto error; 638- } 639- if (read(fd, map->p, map->len) != (ssize_t)map->len) { 640- file_badread(ms); 641- goto error; 642- } 643-#endif 644- (void)close(fd); 645- fd = -1; 646+ map->len = CAST(size_t, st.sb.st_size); 647+ map->p = CAST(void *, emalloc(map->len)); 648 649- if (check_buffer(ms, map, dbname) != 0) { 650- goto error; 651- } 652-#ifdef QUICK 653- if (mprotect(map->p, CAST(size_t, st.st_size), PROT_READ) == -1) { 654- file_error(ms, errno, "cannot mprotect `%s'", dbname); 655+ if (php_stream_read(stream, map->p, (size_t)st.sb.st_size) != (size_t)st.sb.st_size) { 656+ file_badread(ms); 657 goto error; 658 } 659-#endif 660- 661- free(dbname); 662- return map; 663- 664-error: 665- if (fd != -1) 666- (void)close(fd); 667- apprentice_unmap(map); 668- free(dbname); 669- return rv; 670-} 671 672-private int 673-check_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname) 674-{ 675- uint32_t *ptr; 676- uint32_t entries, nentries; 677- uint32_t version; 678- int i, needsbyteswap; 679+ php_stream_close(stream); 680+ stream = NULL; 681 682- ptr = CAST(uint32_t *, map->p); 683+internal_loaded: 684+ ptr = (uint32_t *)(void *)map->p; 685 if (*ptr != MAGICNO) { 686 if (swap4(*ptr) != MAGICNO) { 687 file_error(ms, 0, "bad magic in `%s'", dbname); 688- return -1; 689+ goto error; 690 } 691 needsbyteswap = 1; 692 } else 693@@ -3353,17 +3268,29 @@ 694 else 695 version = ptr[1]; 696 if (version != VERSIONNO) { 697- file_error(ms, 0, "File %s supports only version %d magic " 698- "files. `%s' is version %d", VERSION, 699+ file_error(ms, 0, "File %d supports only version %d magic " 700+ "files. `%s' is version %d", MAGIC_VERSION, 701 VERSIONNO, dbname, version); 702- return -1; 703+ goto error; 704 } 705- entries = CAST(uint32_t, map->len / sizeof(struct magic)); 706- if ((entries * sizeof(struct magic)) != map->len) { 707- file_error(ms, 0, "Size of `%s' %" SIZE_T_FORMAT "u is not " 708- "a multiple of %" SIZE_T_FORMAT "u", 709- dbname, map->len, sizeof(struct magic)); 710- return -1; 711+ 712+ /* php_magic_database is a const, performing writes will segfault. This is for big-endian 713+ machines only, PPC and Sparc specifically. Consider static variable or MINIT in 714+ future. */ 715+ if (needsbyteswap && fn == NULL) { 716+ map->p = emalloc(sizeof(php_magic_database)); 717+ map->p = memcpy(map->p, php_magic_database, sizeof(php_magic_database)); 718+ } 719+ 720+ if (NULL != fn) { 721+ nentries = (uint32_t)(st.sb.st_size / sizeof(struct magic)); 722+ entries = (uint32_t)(st.sb.st_size / sizeof(struct magic)); 723+ if ((zend_off_t)(entries * sizeof(struct magic)) != st.sb.st_size) { 724+ file_error(ms, 0, "Size of `%s' %llu is not a multiple of %zu", 725+ dbname, (unsigned long long)st.sb.st_size, 726+ sizeof(struct magic)); 727+ goto error; 728+ } 729 } 730 map->magic[0] = CAST(struct magic *, map->p) + 1; 731 nentries = 0; 732@@ -3376,15 +3303,29 @@ 733 map->magic[i + 1] = map->magic[i] + map->nmagic[i]; 734 nentries += map->nmagic[i]; 735 } 736- if (entries != nentries + 1) { 737+ if (NULL != fn && entries != nentries + 1) { 738 file_error(ms, 0, "Inconsistent entries in `%s' %u != %u", 739 dbname, entries, nentries + 1); 740- return -1; 741+ goto error; 742 } 743 if (needsbyteswap) 744 for (i = 0; i < MAGIC_SETS; i++) 745 byteswap(map->magic[i], map->nmagic[i]); 746- return 0; 747+ 748+ if (dbname) { 749+ efree(dbname); 750+ } 751+ return map; 752+ 753+error: 754+ if (stream) { 755+ php_stream_close(stream); 756+ } 757+ apprentice_unmap(map); 758+ if (dbname) { 759+ efree(dbname); 760+ } 761+ return NULL; 762 } 763 764 /* 765@@ -3395,7 +3336,7 @@ 766 { 767 static const size_t nm = sizeof(*map->nmagic) * MAGIC_SETS; 768 static const size_t m = sizeof(**map->magic); 769- int fd = -1; 770+ php_stream *stream; 771 size_t len; 772 char *dbname; 773 int rv = -1; 774@@ -3410,8 +3351,10 @@ 775 if (dbname == NULL) 776 goto out; 777 778- if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) 779- { 780+ /* wb+ == O_WRONLY|O_CREAT|O_TRUNC|O_BINARY */ 781+ stream = php_stream_open_wrapper((char *)fn, "wb+", REPORT_ERRORS, NULL); 782+ 783+ if (!stream) { 784 file_error(ms, errno, "cannot open `%s'", dbname); 785 goto out; 786 } 787@@ -3420,26 +3363,25 @@ 788 hdr.h[1] = VERSIONNO; 789 memcpy(hdr.h + 2, map->nmagic, nm); 790 791- if (write(fd, &hdr, sizeof(hdr)) != CAST(ssize_t, sizeof(hdr))) { 792+ if (php_stream_write(stream,(const char *)&hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr)) { 793 file_error(ms, errno, "error writing `%s'", dbname); 794- goto out2; 795+ goto out; 796 } 797 798 for (i = 0; i < MAGIC_SETS; i++) { 799 len = m * map->nmagic[i]; 800- if (write(fd, map->magic[i], len) != CAST(ssize_t, len)) { 801+ if (php_stream_write(stream, (const char *)map->magic[i], len) != (ssize_t)len) { 802 file_error(ms, errno, "error writing `%s'", dbname); 803- goto out2; 804+ goto out; 805 } 806 } 807 808 rv = 0; 809-out2: 810- if (fd != -1) 811- (void)close(fd); 812+ if (stream) { 813+ php_stream_close(stream); 814+ } 815 out: 816- apprentice_unmap(map); 817- free(dbname); 818+ efree(dbname); 819 return rv; 820 } 821 822@@ -3473,17 +3415,18 @@ 823 q++; 824 /* Compatibility with old code that looked in .mime */ 825 if (ms->flags & MAGIC_MIME) { 826- if (asprintf(&buf, "%.*s.mime%s", CAST(int, q - fn), fn, ext) 827- < 0) 828- return NULL; 829- if (access(buf, R_OK) != -1) { 830+ spprintf(&buf, MAXPATHLEN, "%.*s.mime%s", CAST(int, q - fn), fn, ext); 831+#ifdef PHP_WIN32 832+ if (VCWD_ACCESS(buf, R_OK) == 0) { 833+#else 834+ if (VCWD_ACCESS(buf, R_OK) != -1) { 835+#endif 836 ms->flags &= MAGIC_MIME_TYPE; 837 return buf; 838 } 839- free(buf); 840+ efree(buf); 841 } 842- if (asprintf(&buf, "%.*s%s", CAST(int, q - fn), fn, ext) < 0) 843- return NULL; 844+ spprintf(&buf, MAXPATHLEN, "%.*s%s", CAST(int, q - fn), fn, ext); 845 846 /* Compatibility with old code that looked in .mime */ 847 if (strstr(fn, ".mime") != NULL) 848@@ -3605,7 +3548,7 @@ 849 m->offset = swap4(CAST(uint32_t, m->offset)); 850 m->in_offset = swap4(CAST(uint32_t, m->in_offset)); 851 m->lineno = swap4(CAST(uint32_t, m->lineno)); 852- if (IS_STRING(m->type)) { 853+ if (IS_LIBMAGIC_STRING(m->type)) { 854 m->str_range = swap4(m->str_range); 855 m->str_flags = swap4(m->str_flags); 856 } 857@@ -3702,7 +3645,6 @@ 858 continue; 859 if (strcmp(ma[i].value.s, name) == 0) { 860 v->magic = &ma[i]; 861- v->magic_rxcomp = &(ml->magic_rxcomp[i]); 862 for (j = i + 1; j < ml->nmagic; j++) 863 if (ma[j].cont_level == 0) 864 break; 865diff -u libmagic.orig/ascmagic.c libmagic/ascmagic.c 866--- libmagic.orig/ascmagic.c 2022-09-13 20:40:30.000000000 +0200 867+++ libmagic/ascmagic.c 2024-02-13 21:14:11.091069093 +0100 868@@ -96,7 +96,7 @@ 869 rv = file_ascmagic_with_encoding(ms, &bb, 870 ubuf, ulen, code, type, text); 871 872- free(ubuf); 873+ efree(ubuf); 874 875 return rv; 876 } 877@@ -143,13 +143,15 @@ 878 /* malloc size is a conservative overestimate; could be 879 improved, or at least realloced after conversion. */ 880 mlen = ulen * 6; 881- if ((utf8_buf = CAST(unsigned char *, malloc(mlen))) == NULL) { 882+ if ((utf8_buf = CAST(unsigned char *, emalloc(mlen))) == NULL) { 883 file_oomem(ms, mlen); 884 goto done; 885 } 886 if ((utf8_end = encode_utf8(utf8_buf, mlen, ubuf, ulen)) 887- == NULL) 888+ == NULL) { 889+ rv = 0; 890 goto done; 891+ } 892 buffer_init(&bb, b->fd, &b->st, utf8_buf, 893 CAST(size_t, utf8_end - utf8_buf)); 894 895@@ -273,8 +275,8 @@ 896 goto done; 897 898 if (has_long_lines) 899- if (file_printf(ms, ", with very long lines (%" 900- SIZE_T_FORMAT "u)", has_long_lines) == -1) 901+ if (file_printf(ms, ", with very long lines (%zu)", 902+ has_long_lines) == -1) 903 goto done; 904 905 /* 906@@ -330,7 +332,8 @@ 907 } 908 rv = 1; 909 done: 910- free(utf8_buf); 911+ if (utf8_buf) 912+ efree(utf8_buf); 913 914 return rv; 915 } 916diff -u libmagic.orig/buffer.c libmagic/buffer.c 917--- libmagic.orig/buffer.c 2022-09-13 20:34:20.000000000 +0200 918+++ libmagic/buffer.c 2023-10-25 17:56:17.069962152 +0200 919@@ -31,19 +31,21 @@ 920 #endif /* lint */ 921 922 #include "magic.h" 923+#ifdef HAVE_UNISTD_H 924 #include <unistd.h> 925+#endif 926 #include <string.h> 927 #include <stdlib.h> 928 #include <sys/stat.h> 929 930 void 931-buffer_init(struct buffer *b, int fd, const struct stat *st, const void *data, 932+buffer_init(struct buffer *b, int fd, const zend_stat_t *st, const void *data, 933 size_t len) 934 { 935 b->fd = fd; 936 if (st) 937 memcpy(&b->st, st, sizeof(b->st)); 938- else if (b->fd == -1 || fstat(b->fd, &b->st) == -1) 939+ else if (b->fd == -1 || zend_fstat(b->fd, &b->st) == -1) 940 memset(&b->st, 0, sizeof(b->st)); 941 b->fbuf = data; 942 b->flen = len; 943@@ -55,7 +57,7 @@ 944 void 945 buffer_fini(struct buffer *b) 946 { 947- free(b->ebuf); 948+ efree(b->ebuf); 949 } 950 951 int 952@@ -71,12 +73,14 @@ 953 954 b->elen = CAST(size_t, b->st.st_size) < b->flen ? 955 CAST(size_t, b->st.st_size) : b->flen; 956- if ((b->ebuf = malloc(b->elen)) == NULL) 957+ if ((b->ebuf = emalloc(b->elen)) == NULL) 958 goto out; 959 960 b->eoff = b->st.st_size - b->elen; 961- if (pread(b->fd, b->ebuf, b->elen, b->eoff) == -1) { 962- free(b->ebuf); 963+ if (FINFO_LSEEK_FUNC(b->fd, b->eoff, SEEK_SET) == (zend_off_t)-1 || 964+ FINFO_READ_FUNC(b->fd, b->ebuf, b->elen) != (ssize_t)b->elen) 965+ { 966+ efree(b->ebuf); 967 b->ebuf = NULL; 968 goto out; 969 } 970diff -u libmagic.orig/cdf.c libmagic/cdf.c 971--- libmagic.orig/cdf.c 2022-09-13 20:34:25.000000000 +0200 972+++ libmagic/cdf.c 2023-10-25 17:56:17.069962152 +0200 973@@ -43,7 +43,9 @@ 974 #include <err.h> 975 #endif 976 #include <stdlib.h> 977+#ifdef HAVE_UNISTD_H 978 #include <unistd.h> 979+#endif 980 #include <string.h> 981 #include <time.h> 982 #include <ctype.h> 983@@ -91,44 +93,9 @@ 984 CDF_TOLE8(CAST(uint64_t, x)))) 985 #define CDF_GETUINT32(x, y) cdf_getuint32(x, y) 986 987-#define CDF_MALLOC(n) cdf_malloc(__FILE__, __LINE__, (n)) 988-#define CDF_REALLOC(p, n) cdf_realloc(__FILE__, __LINE__, (p), (n)) 989-#define CDF_CALLOC(n, u) cdf_calloc(__FILE__, __LINE__, (n), (u)) 990- 991- 992-/*ARGSUSED*/ 993-static void * 994-cdf_malloc(const char *file __attribute__((__unused__)), 995- size_t line __attribute__((__unused__)), size_t n) 996-{ 997- DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u\n", 998- file, line, __func__, n)); 999- if (n == 0) 1000- n++; 1001- return malloc(n); 1002-} 1003- 1004-/*ARGSUSED*/ 1005-static void * 1006-cdf_realloc(const char *file __attribute__((__unused__)), 1007- size_t line __attribute__((__unused__)), void *p, size_t n) 1008-{ 1009- DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u\n", 1010- file, line, __func__, n)); 1011- return realloc(p, n); 1012-} 1013- 1014-/*ARGSUSED*/ 1015-static void * 1016-cdf_calloc(const char *file __attribute__((__unused__)), 1017- size_t line __attribute__((__unused__)), size_t n, size_t u) 1018-{ 1019- DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u %" 1020- SIZE_T_FORMAT "u\n", file, line, __func__, n, u)); 1021- if (n == 0) 1022- n++; 1023- return calloc(n, u); 1024-} 1025+#define CDF_MALLOC(n) emalloc(n) 1026+#define CDF_REALLOC(p, n) erealloc(p, n) 1027+#define CDF_CALLOC(n, u) ecalloc(n, u) 1028 1029 #if defined(HAVE_BYTESWAP_H) 1030 # define _cdf_tole2(x) bswap_16(x) 1031@@ -334,7 +301,7 @@ 1032 scn->sst_len = 0; 1033 scn->sst_dirlen = 0; 1034 scn->sst_ss = 0; 1035- free(scn->sst_tab); 1036+ efree(scn->sst_tab); 1037 scn->sst_tab = NULL; 1038 return -1; 1039 } 1040@@ -342,9 +309,11 @@ 1041 static size_t 1042 cdf_check_stream(const cdf_stream_t *sst, const cdf_header_t *h) 1043 { 1044+#ifndef NDEBUG 1045 size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? 1046 CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); 1047 assert(ss == sst->sst_ss); 1048+#endif 1049 return sst->sst_ss; 1050 } 1051 1052@@ -367,11 +336,11 @@ 1053 } 1054 1055 static ssize_t 1056-cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len) 1057+cdf_read(const cdf_info_t *info, zend_off_t off, void *buf, size_t len) 1058 { 1059 size_t siz = CAST(size_t, off + len); 1060 1061- if (CAST(off_t, off + len) != CAST(off_t, siz)) 1062+ if (CAST(zend_off_t, off + len) != CAST(zend_off_t, siz)) 1063 goto out; 1064 1065 if (info->i_buf != NULL && info->i_len >= siz) { 1066@@ -382,7 +351,10 @@ 1067 if (info->i_fd == -1) 1068 goto out; 1069 1070- if (pread(info->i_fd, buf, len, off) != CAST(ssize_t, len)) 1071+ if (FINFO_LSEEK_FUNC(info->i_fd, off, SEEK_SET) == (zend_off_t)-1) 1072+ return -1; 1073+ 1074+ if (FINFO_READ_FUNC(info->i_fd, buf, len) != (ssize_t)len) 1075 return -1; 1076 1077 return CAST(ssize_t, len); 1078@@ -397,7 +369,7 @@ 1079 char buf[512]; 1080 1081 (void)memcpy(cdf_bo.s, "\01\02\03\04", 4); 1082- if (cdf_read(info, CAST(off_t, 0), buf, sizeof(buf)) == -1) 1083+ if (cdf_read(info, CAST(zend_off_t, 0), buf, sizeof(buf)) == -1) 1084 return -1; 1085 cdf_unpack_header(h, buf); 1086 cdf_swap_header(h); 1087@@ -544,14 +516,14 @@ 1088 } 1089 out: 1090 sat->sat_len = i; 1091- free(msa); 1092+ efree(msa); 1093 return 0; 1094 out3: 1095 errno = EFTYPE; 1096 out2: 1097- free(msa); 1098+ efree(msa); 1099 out1: 1100- free(sat->sat_tab); 1101+ efree(sat->sat_tab); 1102 return -1; 1103 } 1104 1105@@ -719,7 +691,7 @@ 1106 return -1; 1107 1108 if ((buf = CAST(char *, CDF_MALLOC(ss))) == NULL) { 1109- free(dir->dir_tab); 1110+ efree(dir->dir_tab); 1111 return -1; 1112 } 1113 1114@@ -742,11 +714,11 @@ 1115 if (NEED_SWAP) 1116 for (i = 0; i < dir->dir_len; i++) 1117 cdf_swap_dir(&dir->dir_tab[i]); 1118- free(buf); 1119+ efree(buf); 1120 return 0; 1121 out: 1122- free(dir->dir_tab); 1123- free(buf); 1124+ efree(dir->dir_tab); 1125+ efree(buf); 1126 errno = EFTYPE; 1127 return -1; 1128 } 1129@@ -791,7 +763,7 @@ 1130 out: 1131 errno = EFTYPE; 1132 out1: 1133- free(ssat->sat_tab); 1134+ efree(ssat->sat_tab); 1135 return -1; 1136 } 1137 1138@@ -953,7 +925,7 @@ 1139 *maxcount = newcount; 1140 return inp; 1141 out: 1142- free(*info); 1143+ efree(*info); 1144 *maxcount = 0; 1145 *info = NULL; 1146 return NULL; 1147@@ -1136,7 +1108,7 @@ 1148 } 1149 return 0; 1150 out: 1151- free(*info); 1152+ efree(*info); 1153 *info = NULL; 1154 *count = 0; 1155 *maxcount = 0; 1156@@ -1428,7 +1400,7 @@ 1157 cdf_directory_t *d; 1158 char name[__arraycount(d->d_name)]; 1159 cdf_stream_t scn; 1160- struct timespec ts; 1161+ struct timeval ts; 1162 1163 static const char *types[] = { "empty", "user storage", 1164 "user stream", "lockbytes", "property", "root storage" }; 1165@@ -1470,7 +1442,7 @@ 1166 break; 1167 } 1168 cdf_dump_stream(&scn); 1169- free(scn.sst_tab); 1170+ efree(scn.sst_tab); 1171 break; 1172 default: 1173 break; 1174@@ -1483,7 +1455,7 @@ 1175 cdf_dump_property_info(const cdf_property_info_t *info, size_t count) 1176 { 1177 cdf_timestamp_t tp; 1178- struct timespec ts; 1179+ struct timeval ts; 1180 char buf[64]; 1181 size_t i, j; 1182 1183@@ -1568,7 +1540,7 @@ 1184 (void)fprintf(stderr, "Class %s\n", buf); 1185 (void)fprintf(stderr, "Count %d\n", ssi.si_count); 1186 cdf_dump_property_info(info, count); 1187- free(info); 1188+ efree(info); 1189 } 1190 1191 1192@@ -1589,7 +1561,7 @@ 1193 cdf_u16tos8(sbuf, ce[i].ce_namlen, ce[i].ce_name), 1194 cdf_ctime(&ts.tv_sec, tbuf)); 1195 } 1196- free(cat); 1197+ efree(cat); 1198 } 1199 1200 #endif 1201diff -u libmagic.orig/cdf.h libmagic/cdf.h 1202--- libmagic.orig/cdf.h 2022-09-13 20:34:29.000000000 +0200 1203+++ libmagic/cdf.h 2023-10-25 17:56:17.069962152 +0200 1204@@ -37,8 +37,6 @@ 1205 1206 #ifdef WIN32 1207 #include <winsock2.h> 1208-#define timespec timeval 1209-#define tv_nsec tv_usec 1210 #endif 1211 #ifdef __DJGPP__ 1212 #define timespec timeval 1213diff -u libmagic.orig/compress.c libmagic/compress.c 1214--- libmagic.orig/compress.c 2022-09-13 20:34:42.000000000 +0200 1215+++ libmagic/compress.c 2023-10-25 17:56:17.069962152 +0200 1216@@ -63,13 +63,14 @@ 1217 #if defined(HAVE_SYS_TIME_H) 1218 #include <sys/time.h> 1219 #endif 1220- 1221-#if defined(HAVE_ZLIB_H) && defined(ZLIBSUPPORT) 1222+#if defined(HAVE_ZLIB_H) && defined(PHP_FILEINFO_UNCOMPRESS) 1223 #define BUILTIN_DECOMPRESS 1224 #include <zlib.h> 1225 #endif 1226 1227-#if defined(HAVE_BZLIB_H) && defined(BZLIBSUPPORT) 1228+#undef FIONREAD 1229+ 1230+#if defined(PHP_FILEINFO_UNCOMPRESS) 1231 #define BUILTIN_BZLIB 1232 #include <bzlib.h> 1233 #endif 1234@@ -121,6 +122,8 @@ 1235 } 1236 #endif 1237 1238+#ifdef PHP_FILEINFO_UNCOMPRESS 1239+ 1240 static int 1241 lzmacmp(const unsigned char *buf) 1242 { 1243@@ -297,7 +300,7 @@ 1244 if (urv == ERRDATA) 1245 prv = format_decompression_error(ms, i, newbuf); 1246 else 1247- prv = file_buffer(ms, -1, NULL, name, newbuf, nsz); 1248+ prv = file_buffer(ms, NULL, NULL, name, newbuf, nsz); 1249 if (prv == -1) 1250 goto error; 1251 rv = 1; 1252@@ -314,17 +317,17 @@ 1253 * XXX: If file_buffer fails here, we overwrite 1254 * the compressed text. FIXME. 1255 */ 1256- if (file_buffer(ms, -1, NULL, NULL, buf, nbytes) == -1) { 1257+ if (file_buffer(ms, NULL, NULL, NULL, buf, nbytes) == -1) { 1258 if (file_pop_buffer(ms, pb) != NULL) 1259 abort(); 1260 goto error; 1261 } 1262 if ((rbuf = file_pop_buffer(ms, pb)) != NULL) { 1263 if (file_printf(ms, "%s", rbuf) == -1) { 1264- free(rbuf); 1265+ efree(rbuf); 1266 goto error; 1267 } 1268- free(rbuf); 1269+ efree(rbuf); 1270 } 1271 if (!mime && file_printf(ms, ")") == -1) 1272 goto error; 1273@@ -345,7 +348,8 @@ 1274 if (sa_saved && sig_act.sa_handler != SIG_IGN) 1275 (void)sigaction(SIGPIPE, &sig_act, NULL); 1276 1277- free(newbuf); 1278+ if (newbuf) 1279+ efree(newbuf); 1280 ms->flags |= MAGIC_COMPRESS; 1281 DPRINTF("Zmagic returns %d\n", rv); 1282 return rv; 1283@@ -428,7 +432,7 @@ 1284 1285 nocheck: 1286 do 1287- switch ((rv = read(fd, buf, n))) { 1288+ switch ((rv = FINFO_READ_FUNC(fd, buf, n))) { 1289 case -1: 1290 if (errno == EINTR) 1291 continue; 1292@@ -521,13 +525,13 @@ 1293 return -1; 1294 } 1295 (void)close(tfd); 1296- if (lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1)) { 1297+ if (FINFO_LSEEK_FUNC(fd, (zend_off_t)0, SEEK_SET) == (zend_off_t)-1) { 1298 file_badseek(ms); 1299 return -1; 1300 } 1301 return fd; 1302 } 1303-#if HAVE_FORK 1304+#ifdef PHP_FILEINFO_UNCOMPRESS 1305 #ifdef BUILTIN_DECOMPRESS 1306 1307 #define FHCRC (1 << 1) 1308@@ -578,7 +582,7 @@ 1309 int rc; 1310 z_stream z; 1311 1312- if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL) 1313+ if ((*newch = CAST(unsigned char *, emalloc(bytes_max + 1))) == NULL) 1314 return makeerror(newch, n, "No buffer, %s", strerror(errno)); 1315 1316 z.next_in = CCAST(Bytef *, old); 1317@@ -1048,3 +1052,4 @@ 1318 return rv; 1319 } 1320 #endif 1321+#endif 1322diff -u libmagic.orig/der.c libmagic/der.c 1323--- libmagic.orig/der.c 2022-09-13 20:34:54.000000000 +0200 1324+++ libmagic/der.c 2023-10-25 17:56:17.069962152 +0200 1325@@ -54,7 +54,9 @@ 1326 #include "magic.h" 1327 #include "der.h" 1328 #else 1329+#ifdef HAVE_SYS_MMAN_H 1330 #include <sys/mman.h> 1331+#endif 1332 #include <sys/stat.h> 1333 #include <err.h> 1334 #endif 1335diff -u libmagic.orig/elfclass.h libmagic/elfclass.h 1336--- libmagic.orig/elfclass.h 2022-09-13 20:35:11.000000000 +0200 1337+++ libmagic/elfclass.h 2023-08-30 22:16:33.784980199 +0200 1338@@ -41,7 +41,7 @@ 1339 return toomany(ms, "program headers", phnum); 1340 flags |= FLAGS_IS_CORE; 1341 if (dophn_core(ms, clazz, swap, fd, 1342- CAST(off_t, elf_getu(swap, elfhdr.e_phoff)), phnum, 1343+ CAST(zend_off_t, elf_getu(swap, elfhdr.e_phoff)), phnum, 1344 CAST(size_t, elf_getu16(swap, elfhdr.e_phentsize)), 1345 fsize, &flags, ¬ecount) == -1) 1346 return -1; 1347@@ -56,7 +56,7 @@ 1348 if (shnum > ms->elf_shnum_max) 1349 return toomany(ms, "section", shnum); 1350 if (dophn_exec(ms, clazz, swap, fd, 1351- CAST(off_t, elf_getu(swap, elfhdr.e_phoff)), phnum, 1352+ CAST(zend_off_t, elf_getu(swap, elfhdr.e_phoff)), phnum, 1353 CAST(size_t, elf_getu16(swap, elfhdr.e_phentsize)), 1354 fsize, shnum, &flags, ¬ecount) == -1) 1355 return -1; 1356@@ -66,7 +66,7 @@ 1357 if (shnum > ms->elf_shnum_max) 1358 return toomany(ms, "section headers", shnum); 1359 if (doshn(ms, clazz, swap, fd, 1360- CAST(off_t, elf_getu(swap, elfhdr.e_shoff)), shnum, 1361+ CAST(zend_off_t, elf_getu(swap, elfhdr.e_shoff)), shnum, 1362 CAST(size_t, elf_getu16(swap, elfhdr.e_shentsize)), 1363 fsize, elf_getu16(swap, elfhdr.e_machine), 1364 CAST(int, elf_getu16(swap, elfhdr.e_shstrndx)), 1365diff -u libmagic.orig/encoding.c libmagic/encoding.c 1366--- libmagic.orig/encoding.c 2022-09-13 20:46:07.000000000 +0200 1367+++ libmagic/encoding.c 2023-10-25 17:56:17.069962152 +0200 1368@@ -97,7 +97,7 @@ 1369 nbytes = ms->encoding_max; 1370 1371 mlen = (nbytes + 1) * sizeof((*ubuf)[0]); 1372- *ubuf = CAST(file_unichar_t *, calloc(CAST(size_t, 1), mlen)); 1373+ *ubuf = CAST(file_unichar_t *, ecalloc(CAST(size_t, 1), mlen)); 1374 if (*ubuf == NULL) { 1375 file_oomem(ms, mlen); 1376 goto done; 1377@@ -150,7 +150,7 @@ 1378 unsigned char *nbuf; 1379 1380 mlen = (nbytes + 1) * sizeof(nbuf[0]); 1381- if ((nbuf = CAST(unsigned char *, malloc(mlen))) == NULL) { 1382+ if ((nbuf = CAST(unsigned char *, emalloc(mlen))) == NULL) { 1383 file_oomem(ms, mlen); 1384 goto done; 1385 } 1386@@ -170,12 +170,12 @@ 1387 rv = 0; 1388 *type = "binary"; 1389 } 1390- free(nbuf); 1391+ efree(nbuf); 1392 } 1393 1394 done: 1395 if (ubuf == &udefbuf) 1396- free(udefbuf); 1397+ efree(udefbuf); 1398 1399 return rv; 1400 } 1401diff -u libmagic.orig/file.h libmagic/file.h 1402--- libmagic.orig/file.h 2022-09-13 20:35:30.000000000 +0200 1403+++ libmagic/file.h 2023-10-25 17:56:17.069962152 +0200 1404@@ -33,9 +33,7 @@ 1405 #ifndef __file_h__ 1406 #define __file_h__ 1407 1408-#ifdef HAVE_CONFIG_H 1409-#include <config.h> 1410-#endif 1411+#include "config.h" 1412 1413 #ifdef HAVE_STDINT_H 1414 #include <stdint.h> 1415@@ -79,8 +77,7 @@ 1416 #include <stdio.h> /* Include that here, to make sure __P gets defined */ 1417 #include <errno.h> 1418 #include <fcntl.h> /* For open and flags */ 1419-#include <regex.h> 1420-#include <time.h> 1421+ 1422 #include <sys/types.h> 1423 #ifndef WIN32 1424 #include <sys/param.h> 1425@@ -88,10 +85,6 @@ 1426 /* Do this here and now, because struct stat gets re-defined on solaris */ 1427 #include <sys/stat.h> 1428 #include <stdarg.h> 1429-#include <locale.h> 1430-#if defined(HAVE_XLOCALE_H) 1431-#include <xlocale.h> 1432-#endif 1433 1434 #define ENABLE_CONDITIONALS 1435 1436@@ -171,14 +164,12 @@ 1437 #define FILE_COMPILE 2 1438 #define FILE_LIST 3 1439 1440-typedef regex_t file_regex_t; 1441- 1442 struct buffer { 1443 int fd; 1444- struct stat st; 1445+ zend_stat_t st; 1446 const void *fbuf; 1447 size_t flen; 1448- off_t eoff; 1449+ zend_off_t eoff; 1450 void *ebuf; 1451 size_t elen; 1452 }; 1453@@ -281,7 +272,7 @@ 1454 #define FILE_OCTAL 59 1455 #define FILE_NAMES_SIZE 60 /* size of array to contain all names */ 1456 1457-#define IS_STRING(t) \ 1458+#define IS_LIBMAGIC_STRING(t) \ 1459 ((t) == FILE_STRING || \ 1460 (t) == FILE_PSTRING || \ 1461 (t) == FILE_BESTRING16 || \ 1462@@ -412,7 +403,6 @@ 1463 /* list of magic entries */ 1464 struct mlist { 1465 struct magic *magic; /* array of magic entries */ 1466- file_regex_t **magic_rxcomp; /* array of compiled regexps */ 1467 size_t nmagic; /* number of entries in array */ 1468 void *map; /* internal resources used by entry */ 1469 struct mlist *next, *prev; 1470@@ -515,10 +505,9 @@ 1471 protected const char *file_fmtnum(char *, size_t, const char *, int); 1472 protected struct magic_set *file_ms_alloc(int); 1473 protected void file_ms_free(struct magic_set *); 1474-protected int file_default(struct magic_set *, size_t); 1475-protected int file_buffer(struct magic_set *, int, struct stat *, const char *, 1476- const void *, size_t); 1477-protected int file_fsmagic(struct magic_set *, const char *, struct stat *); 1478+protected int file_buffer(struct magic_set *, php_stream *, zend_stat_t *, const char *, const void *, 1479+ size_t); 1480+protected int file_fsmagic(struct magic_set *, const char *, zend_stat_t *); 1481 protected int file_pipe2file(struct magic_set *, int, const void *, size_t); 1482 protected int file_vprintf(struct magic_set *, const char *, va_list) 1483 __attribute__((__format__(__printf__, 2, 0))); 1484@@ -534,7 +523,7 @@ 1485 protected int file_reset(struct magic_set *, int); 1486 protected int file_tryelf(struct magic_set *, const struct buffer *); 1487 protected int file_trycdf(struct magic_set *, const struct buffer *); 1488-#if HAVE_FORK 1489+#ifdef PHP_FILEINFO_UNCOMPRESS 1490 protected int file_zmagic(struct magic_set *, const struct buffer *, 1491 const char *); 1492 #endif 1493@@ -588,19 +577,11 @@ 1494 protected int file_clear_closexec(int); 1495 protected char *file_strtrim(char *); 1496 1497-protected void buffer_init(struct buffer *, int, const struct stat *, 1498+protected void buffer_init(struct buffer *, int, const zend_stat_t *, 1499 const void *, size_t); 1500 protected void buffer_fini(struct buffer *); 1501 protected int buffer_fill(const struct buffer *); 1502 1503- 1504- 1505-protected int file_regcomp(struct magic_set *, file_regex_t *, const char *, 1506- int); 1507-protected int file_regexec(struct magic_set *, file_regex_t *, const char *, 1508- size_t, regmatch_t *, int); 1509-protected void file_regfree(file_regex_t *); 1510- 1511 typedef struct { 1512 char *buf; 1513 size_t blen; 1514@@ -615,23 +596,10 @@ 1515 extern const size_t file_nnames; 1516 #endif 1517 1518-#ifndef HAVE_PREAD 1519-ssize_t pread(int, void *, size_t, off_t); 1520-#endif 1521-#ifndef HAVE_VASPRINTF 1522-int vasprintf(char **, const char *, va_list); 1523-#endif 1524-#ifndef HAVE_ASPRINTF 1525-int asprintf(char **, const char *, ...); 1526-#endif 1527-#ifndef HAVE_DPRINTF 1528-int dprintf(int, const char *, ...); 1529-#endif 1530- 1531-#ifndef HAVE_STRLCPY 1532+#ifndef strlcpy 1533 size_t strlcpy(char *, const char *, size_t); 1534 #endif 1535-#ifndef HAVE_STRLCAT 1536+#ifndef strlcat 1537 size_t strlcat(char *, const char *, size_t); 1538 #endif 1539 #ifndef HAVE_STRCASESTR 1540@@ -647,39 +615,6 @@ 1541 #ifndef HAVE_ASCTIME_R 1542 char *asctime_r(const struct tm *, char *); 1543 #endif 1544-#ifndef HAVE_GMTIME_R 1545-struct tm *gmtime_r(const time_t *, struct tm *); 1546-#endif 1547-#ifndef HAVE_LOCALTIME_R 1548-struct tm *localtime_r(const time_t *, struct tm *); 1549-#endif 1550-#ifndef HAVE_FMTCHECK 1551-const char *fmtcheck(const char *, const char *) 1552- __attribute__((__format_arg__(2))); 1553-#endif 1554- 1555-#ifdef HAVE_LIBSECCOMP 1556-// basic filter 1557-// this mode should not interfere with normal operations 1558-// only some dangerous syscalls are blacklisted 1559-int enable_sandbox_basic(void); 1560- 1561-// enhanced filter 1562-// this mode allows only the necessary syscalls used during normal operation 1563-// extensive testing required !!! 1564-int enable_sandbox_full(void); 1565-#endif 1566- 1567-protected const char *file_getprogname(void); 1568-protected void file_setprogname(const char *); 1569-protected void file_err(int, const char *, ...) 1570- __attribute__((__format__(__printf__, 2, 3), __noreturn__)); 1571-protected void file_errx(int, const char *, ...) 1572- __attribute__((__format__(__printf__, 2, 3), __noreturn__)); 1573-protected void file_warn(const char *, ...) 1574- __attribute__((__format__(__printf__, 1, 2))); 1575-protected void file_warnx(const char *, ...) 1576- __attribute__((__format__(__printf__, 1, 2))); 1577 1578 #if defined(HAVE_MMAP) && defined(HAVE_SYS_MMAN_H) && !defined(QUICK) 1579 #define QUICK 1580diff -u libmagic.orig/fsmagic.c libmagic/fsmagic.c 1581--- libmagic.orig/fsmagic.c 2022-09-13 20:36:53.000000000 +0200 1582+++ libmagic/fsmagic.c 2023-10-25 17:56:17.069962152 +0200 1583@@ -66,26 +66,10 @@ 1584 # define minor(dev) ((dev) & 0xff) 1585 #endif 1586 #undef HAVE_MAJOR 1587-#ifdef S_IFLNK 1588-private int 1589-bad_link(struct magic_set *ms, int err, char *buf) 1590-{ 1591- int mime = ms->flags & MAGIC_MIME; 1592- if ((mime & MAGIC_MIME_TYPE) && 1593- file_printf(ms, "inode/symlink") 1594- == -1) 1595- return -1; 1596- else if (!mime) { 1597- if (ms->flags & MAGIC_ERROR) { 1598- file_error(ms, err, 1599- "broken symbolic link to %s", buf); 1600- return -1; 1601- } 1602- if (file_printf(ms, "broken symbolic link to %s", buf) == -1) 1603- return -1; 1604- } 1605- return 1; 1606-} 1607+ 1608+#ifdef PHP_WIN32 1609+ 1610+# undef S_IFIFO 1611 #endif 1612 private int 1613 handle_mime(struct magic_set *ms, int mime, const char *str) 1614@@ -103,60 +87,17 @@ 1615 } 1616 1617 protected int 1618-file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) 1619+file_fsmagic(struct magic_set *ms, const char *fn, zend_stat_t *sb) 1620 { 1621 int ret, did = 0; 1622 int mime = ms->flags & MAGIC_MIME; 1623 int silent = ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION); 1624-#ifdef S_IFLNK 1625- char buf[BUFSIZ+4]; 1626- ssize_t nch; 1627- struct stat tstatbuf; 1628-#endif 1629 1630 if (fn == NULL) 1631 return 0; 1632 1633 #define COMMA (did++ ? ", " : "") 1634- /* 1635- * Fstat is cheaper but fails for files you don't have read perms on. 1636- * On 4.2BSD and similar systems, use lstat() to identify symlinks. 1637- */ 1638-#ifdef S_IFLNK 1639- if ((ms->flags & MAGIC_SYMLINK) == 0) 1640- ret = lstat(fn, sb); 1641- else 1642-#endif 1643- ret = stat(fn, sb); /* don't merge into if; see "ret =" above */ 1644- 1645-#ifdef WIN32 1646- { 1647- HANDLE hFile = CreateFile((LPCSTR)fn, 0, FILE_SHARE_DELETE | 1648- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 1649- NULL); 1650- if (hFile != INVALID_HANDLE_VALUE) { 1651- /* 1652- * Stat failed, but we can still open it - assume it's 1653- * a block device, if nothing else. 1654- */ 1655- if (ret) { 1656- sb->st_mode = S_IFBLK; 1657- ret = 0; 1658- } 1659- switch (GetFileType(hFile)) { 1660- case FILE_TYPE_CHAR: 1661- sb->st_mode |= S_IFCHR; 1662- sb->st_mode &= ~S_IFREG; 1663- break; 1664- case FILE_TYPE_PIPE: 1665- sb->st_mode |= S_IFIFO; 1666- sb->st_mode &= ~S_IFREG; 1667- break; 1668- } 1669- CloseHandle(hFile); 1670- } 1671- } 1672-#endif 1673+ ret = php_sys_stat(fn, sb); 1674 1675 if (ret) { 1676 if (ms->flags & MAGIC_ERROR) { 1677@@ -189,32 +130,24 @@ 1678 } 1679 1680 switch (sb->st_mode & S_IFMT) { 1681- case S_IFDIR: 1682- if (mime) { 1683- if (handle_mime(ms, mime, "directory") == -1) 1684- return -1; 1685- } else if (silent) { 1686- } else if (file_printf(ms, "%sdirectory", COMMA) == -1) 1687- return -1; 1688- break; 1689-#ifdef S_IFCHR 1690- case S_IFCHR: 1691- /* 1692- * If -s has been specified, treat character special files 1693- * like ordinary files. Otherwise, just report that they 1694- * are block special files and go on to the next file. 1695- */ 1696- if ((ms->flags & MAGIC_DEVICES) != 0) { 1697- ret = 0; 1698- break; 1699- } 1700- if (mime) { 1701- if (handle_mime(ms, mime, "chardevice") == -1) 1702- return -1; 1703- } else if (silent) { 1704- } else { 1705-#ifdef HAVE_STRUCT_STAT_ST_RDEV 1706-# ifdef dv_unit 1707+#ifndef PHP_WIN32 1708+# ifdef S_IFCHR 1709+ case S_IFCHR: 1710+ /* 1711+ * If -s has been specified, treat character special files 1712+ * like ordinary files. Otherwise, just report that they 1713+ * are block special files and go on to the next file. 1714+ */ 1715+ if ((ms->flags & MAGIC_DEVICES) != 0) { 1716+ ret = 0; 1717+ break; 1718+ } 1719+ if (mime) { 1720+ if (handle_mime(ms, mime, "chardevice") == -1) 1721+ return -1; 1722+ } else { 1723+# ifdef HAVE_STAT_ST_RDEV 1724+# ifdef dv_unit 1725 if (file_printf(ms, "%scharacter special (%d/%d/%d)", 1726 COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev), 1727 dv_subunit(sb->st_rdev)) == -1) 1728@@ -229,45 +162,11 @@ 1729 if (file_printf(ms, "%scharacter special", COMMA) == -1) 1730 return -1; 1731 #endif 1732- } 1733- break; 1734-#endif 1735-#ifdef S_IFBLK 1736- case S_IFBLK: 1737- /* 1738- * If -s has been specified, treat block special files 1739- * like ordinary files. Otherwise, just report that they 1740- * are block special files and go on to the next file. 1741- */ 1742- if ((ms->flags & MAGIC_DEVICES) != 0) { 1743- ret = 0; 1744- break; 1745- } 1746- if (mime) { 1747- if (handle_mime(ms, mime, "blockdevice") == -1) 1748- return -1; 1749- } else if (silent) { 1750- } else { 1751-#ifdef HAVE_STRUCT_STAT_ST_RDEV 1752-# ifdef dv_unit 1753- if (file_printf(ms, "%sblock special (%d/%d/%d)", 1754- COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev), 1755- dv_subunit(sb->st_rdev)) == -1) 1756- return -1; 1757-# else 1758- if (file_printf(ms, "%sblock special (%ld/%ld)", 1759- COMMA, (long)major(sb->st_rdev), 1760- (long)minor(sb->st_rdev)) == -1) 1761- return -1; 1762+ } 1763+ return 1; 1764 # endif 1765-#else 1766- if (file_printf(ms, "%sblock special", COMMA) == -1) 1767- return -1; 1768 #endif 1769- } 1770- break; 1771-#endif 1772- /* TODO add code to handle V7 MUX and Blit MUX files */ 1773+ 1774 #ifdef S_IFIFO 1775 case S_IFIFO: 1776 if((ms->flags & MAGIC_DEVICES) != 0) 1777@@ -292,92 +191,14 @@ 1778 #endif 1779 #ifdef S_IFLNK 1780 case S_IFLNK: 1781- if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) { 1782+ /* stat is used, if it made here then the link is broken */ 1783 if (ms->flags & MAGIC_ERROR) { 1784- file_error(ms, errno, "unreadable symlink `%s'", 1785- fn); 1786+ file_error(ms, errno, "unreadable symlink `%s'", fn); 1787 return -1; 1788 } 1789- if (mime) { 1790- if (handle_mime(ms, mime, "symlink") == -1) 1791- return -1; 1792- } else if (silent) { 1793- } else if (file_printf(ms, 1794- "%sunreadable symlink `%s' (%s)", COMMA, fn, 1795- strerror(errno)) == -1) 1796- return -1; 1797- break; 1798- } 1799- buf[nch] = '\0'; /* readlink(2) does not do this */ 1800- 1801- /* If broken symlink, say so and quit early. */ 1802-#ifdef __linux__ 1803- /* 1804- * linux procfs/devfs makes symlinks like pipe:[3515864880] 1805- * that we can't stat their readlink output, so stat the 1806- * original filename instead. 1807- */ 1808- if (stat(fn, &tstatbuf) < 0) 1809- return bad_link(ms, errno, buf); 1810-#else 1811- if (*buf == '/') { 1812- if (stat(buf, &tstatbuf) < 0) 1813- return bad_link(ms, errno, buf); 1814- } else { 1815- char *tmp; 1816- char buf2[BUFSIZ+BUFSIZ+4]; 1817- 1818- if ((tmp = CCAST(char *, strrchr(fn, '/'))) == NULL) { 1819- tmp = buf; /* in current directory anyway */ 1820- } else { 1821- if (tmp - fn + 1 > BUFSIZ) { 1822- if (ms->flags & MAGIC_ERROR) { 1823- file_error(ms, 0, 1824- "path too long: `%s'", buf); 1825- return -1; 1826- } 1827- if (mime) { 1828- if (handle_mime(ms, mime, 1829- "x-path-too-long") == -1) 1830- return -1; 1831- } else if (silent) { 1832- } else if (file_printf(ms, 1833- "%spath too long: `%s'", COMMA, 1834- fn) == -1) 1835- return -1; 1836- break; 1837- } 1838- /* take dir part */ 1839- (void)strlcpy(buf2, fn, sizeof buf2); 1840- buf2[tmp - fn + 1] = '\0'; 1841- /* plus (rel) link */ 1842- (void)strlcat(buf2, buf, sizeof buf2); 1843- tmp = buf2; 1844- } 1845- if (stat(tmp, &tstatbuf) < 0) 1846- return bad_link(ms, errno, buf); 1847- } 1848+ return 1; 1849 #endif 1850 1851- /* Otherwise, handle it. */ 1852- if ((ms->flags & MAGIC_SYMLINK) != 0) { 1853- const char *p; 1854- ms->flags &= MAGIC_SYMLINK; 1855- p = magic_file(ms, buf); 1856- ms->flags |= MAGIC_SYMLINK; 1857- if (p == NULL) 1858- return -1; 1859- } else { /* just print what it points to */ 1860- if (mime) { 1861- if (handle_mime(ms, mime, "symlink") == -1) 1862- return -1; 1863- } else if (silent) { 1864- } else if (file_printf(ms, "%ssymbolic link to %s", 1865- COMMA, buf) == -1) 1866- return -1; 1867- } 1868- break; 1869-#endif 1870 #ifdef S_IFSOCK 1871 #ifndef __COHERENT__ 1872 case S_IFSOCK: 1873diff -u libmagic.orig/funcs.c libmagic/funcs.c 1874--- libmagic.orig/funcs.c 2022-09-13 20:46:07.000000000 +0200 1875+++ libmagic/funcs.c 2023-10-25 17:56:17.069962152 +0200 1876@@ -66,7 +66,7 @@ 1877 private void 1878 file_clearbuf(struct magic_set *ms) 1879 { 1880- free(ms->o.buf); 1881+ efree(ms->o.buf); 1882 ms->o.buf = NULL; 1883 ms->o.blen = 0; 1884 } 1885@@ -132,7 +132,7 @@ 1886 protected int 1887 file_vprintf(struct magic_set *ms, const char *fmt, va_list ap) 1888 { 1889- int len; 1890+ size_t len; 1891 char *buf, *newstr; 1892 char tbuf[1024]; 1893 1894@@ -145,31 +145,25 @@ 1895 return -1; 1896 } 1897 1898- len = vasprintf(&buf, fmt, ap); 1899- if (len < 0 || (size_t)len > 1024 || len + ms->o.blen > 1024 * 1024) { 1900+ len = vspprintf(&buf, 0, fmt, ap); 1901+ if (len > 1024 || len + ms->o.blen > 1024 * 1024) { 1902 size_t blen = ms->o.blen; 1903- free(buf); 1904+ if (buf) efree(buf); 1905 file_clearbuf(ms); 1906- file_error(ms, 0, "Output buffer space exceeded %d+%" 1907+ file_error(ms, 0, "Output buffer space exceeded %" SIZE_T_FORMAT "u+%" 1908 SIZE_T_FORMAT "u", len, blen); 1909 return -1; 1910 } 1911 1912 if (ms->o.buf != NULL) { 1913- len = asprintf(&newstr, "%s%s", ms->o.buf, buf); 1914- free(buf); 1915- if (len < 0) 1916- goto out; 1917- free(ms->o.buf); 1918+ len = spprintf(&newstr, 0, "%s%s", ms->o.buf, buf); 1919+ efree(buf); 1920+ efree(ms->o.buf); 1921 buf = newstr; 1922 } 1923 ms->o.buf = buf; 1924 ms->o.blen = len; 1925 return 0; 1926-out: 1927- file_clearbuf(ms); 1928- file_error(ms, errno, "vasprintf failed"); 1929- return -1; 1930 } 1931 1932 protected int 1933@@ -320,8 +314,8 @@ 1934 */ 1935 /*ARGSUSED*/ 1936 protected int 1937-file_buffer(struct magic_set *ms, int fd, struct stat *st, 1938- const char *inname __attribute__ ((__unused__)), 1939+file_buffer(struct magic_set *ms, php_stream *stream, zend_stat_t *st, 1940+ const char *inname, 1941 const void *buf, size_t nb) 1942 { 1943 int m = 0, rv = 0, looks_text = 0; 1944@@ -331,6 +325,19 @@ 1945 const char *ftype = NULL; 1946 char *rbuf = NULL; 1947 struct buffer b; 1948+ int fd = -1; 1949+ 1950+ if (stream) { 1951+#ifdef _WIN64 1952+ php_socket_t _fd = fd; 1953+#else 1954+ int _fd; 1955+#endif 1956+ int _ret = php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&_fd, 0); 1957+ if (SUCCESS == _ret) { 1958+ fd = (int)_fd; 1959+ } 1960+ } 1961 1962 buffer_init(&b, fd, st, buf, nb); 1963 ms->mode = b.st.st_mode; 1964@@ -363,7 +370,8 @@ 1965 } 1966 } 1967 #endif 1968-#if HAVE_FORK 1969+ 1970+#if PHP_FILEINFO_UNCOMPRESS 1971 /* try compression stuff */ 1972 if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0) { 1973 m = file_zmagic(ms, &b, inname); 1974@@ -488,10 +496,10 @@ 1975 if (file_printf(ms, "%s", code_mime) == -1) 1976 rv = -1; 1977 } 1978-#if HAVE_FORK 1979+#if PHP_FILEINFO_UNCOMPRESS 1980 done_encoding: 1981 #endif 1982- free(rbuf); 1983+ efree(rbuf); 1984 buffer_fini(&b); 1985 if (rv) 1986 return rv; 1987@@ -509,7 +517,7 @@ 1988 } 1989 file_clearbuf(ms); 1990 if (ms->o.pbuf) { 1991- free(ms->o.pbuf); 1992+ efree(ms->o.pbuf); 1993 ms->o.pbuf = NULL; 1994 } 1995 ms->event_flags &= ~EVENT_HAD_ERR; 1996@@ -547,7 +555,7 @@ 1997 return NULL; 1998 } 1999 psize = len * 4 + 1; 2000- if ((pbuf = CAST(char *, realloc(ms->o.pbuf, psize))) == NULL) { 2001+ if ((pbuf = CAST(char *, erealloc(ms->o.pbuf, psize))) == NULL) { 2002 file_oomem(ms, psize); 2003 return NULL; 2004 } 2005@@ -611,8 +619,8 @@ 2006 if (level >= ms->c.len) { 2007 len = (ms->c.len = 20 + level) * sizeof(*ms->c.li); 2008 ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ? 2009- malloc(len) : 2010- realloc(ms->c.li, len)); 2011+ emalloc(len) : 2012+ erealloc(ms->c.li, len)); 2013 if (ms->c.li == NULL) { 2014 file_oomem(ms, len); 2015 return -1; 2016@@ -635,87 +643,38 @@ 2017 protected int 2018 file_replace(struct magic_set *ms, const char *pat, const char *rep) 2019 { 2020- file_regex_t rx; 2021- int rc, rv = -1; 2022- 2023- rc = file_regcomp(ms, &rx, pat, REG_EXTENDED); 2024- if (rc == 0) { 2025- regmatch_t rm; 2026- int nm = 0; 2027- while (file_regexec(ms, &rx, ms->o.buf, 1, &rm, 0) == 0) { 2028- ms->o.buf[rm.rm_so] = '\0'; 2029- if (file_printf(ms, "%s%s", rep, 2030- rm.rm_eo != 0 ? ms->o.buf + rm.rm_eo : "") == -1) 2031- goto out; 2032- nm++; 2033- } 2034- rv = nm; 2035+ zend_string *pattern; 2036+ uint32_t opts = 0; 2037+ pcre_cache_entry *pce; 2038+ zend_string *res; 2039+ zend_string *repl; 2040+ size_t rep_cnt = 0; 2041+ 2042+ opts |= PCRE2_MULTILINE; 2043+ pattern = convert_libmagic_pattern((char*)pat, strlen(pat), opts); 2044+ if ((pce = pcre_get_compiled_regex_cache_ex(pattern, 0)) == NULL) { 2045+ zend_string_release(pattern); 2046+ rep_cnt = -1; 2047+ goto out; 2048+ } 2049+ zend_string_release(pattern); 2050+ 2051+ repl = zend_string_init(rep, strlen(rep), 0); 2052+ res = php_pcre_replace_impl(pce, NULL, ms->o.buf, strlen(ms->o.buf), repl, -1, &rep_cnt); 2053+ 2054+ zend_string_release_ex(repl, 0); 2055+ if (NULL == res) { 2056+ rep_cnt = -1; 2057+ goto out; 2058 } 2059-out: 2060- file_regfree(&rx); 2061- return rv; 2062-} 2063 2064-protected int 2065-file_regcomp(struct magic_set *ms file_locale_used, file_regex_t *rx, 2066- const char *pat, int flags) 2067-{ 2068-#ifdef USE_C_LOCALE 2069- locale_t old = uselocale(ms->c_lc_ctype); 2070- assert(old != NULL); 2071-#else 2072- char old[1024]; 2073- strlcpy(old, setlocale(LC_CTYPE, NULL), sizeof(old)); 2074- (void)setlocale(LC_CTYPE, "C"); 2075-#endif 2076- int rc; 2077- rc = regcomp(rx, pat, flags); 2078+ strncpy(ms->o.buf, ZSTR_VAL(res), ZSTR_LEN(res)); 2079+ ms->o.buf[ZSTR_LEN(res)] = '\0'; 2080 2081-#ifdef USE_C_LOCALE 2082- uselocale(old); 2083-#else 2084- (void)setlocale(LC_CTYPE, old); 2085-#endif 2086- if (rc > 0 && (ms->flags & MAGIC_CHECK)) { 2087- char errmsg[512]; 2088- 2089- (void)regerror(rc, rx, errmsg, sizeof(errmsg)); 2090- file_magerror(ms, "regex error %d for `%s', (%s)", rc, pat, 2091- errmsg); 2092- } 2093- return rc; 2094-} 2095+ zend_string_release_ex(res, 0); 2096 2097-/*ARGSUSED*/ 2098-protected int 2099-file_regexec(struct magic_set *ms file_locale_used, file_regex_t *rx, 2100- const char *str, size_t nmatch, regmatch_t* pmatch, int eflags) 2101-{ 2102-#ifdef USE_C_LOCALE 2103- locale_t old = uselocale(ms->c_lc_ctype); 2104- assert(old != NULL); 2105-#else 2106- char old[1024]; 2107- strlcpy(old, setlocale(LC_CTYPE, NULL), sizeof(old)); 2108- (void)setlocale(LC_CTYPE, "C"); 2109-#endif 2110- int rc; 2111- /* XXX: force initialization because glibc does not always do this */ 2112- if (nmatch != 0) 2113- memset(pmatch, 0, nmatch * sizeof(*pmatch)); 2114- rc = regexec(rx, str, nmatch, pmatch, eflags); 2115-#ifdef USE_C_LOCALE 2116- uselocale(old); 2117-#else 2118- (void)setlocale(LC_CTYPE, old); 2119-#endif 2120- return rc; 2121-} 2122- 2123-protected void 2124-file_regfree(file_regex_t *rx) 2125-{ 2126- regfree(rx); 2127+out: 2128+ return rep_cnt; 2129 } 2130 2131 protected file_pushbuf_t * 2132@@ -726,7 +685,7 @@ 2133 if (ms->event_flags & EVENT_HAD_ERR) 2134 return NULL; 2135 2136- if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL) 2137+ if ((pb = (CAST(file_pushbuf_t *, emalloc(sizeof(*pb))))) == NULL) 2138 return NULL; 2139 2140 pb->buf = ms->o.buf; 2141@@ -746,8 +705,8 @@ 2142 char *rbuf; 2143 2144 if (ms->event_flags & EVENT_HAD_ERR) { 2145- free(pb->buf); 2146- free(pb); 2147+ efree(pb->buf); 2148+ efree(pb); 2149 return NULL; 2150 } 2151 2152@@ -757,7 +716,7 @@ 2153 ms->o.blen = pb->blen; 2154 ms->offset = pb->offset; 2155 2156- free(pb); 2157+ efree(pb); 2158 return rbuf; 2159 } 2160 2161@@ -841,6 +800,7 @@ 2162 #endif 2163 } 2164 2165+#if 0 2166 protected int 2167 file_pipe_closexec(int *fds) 2168 { 2169@@ -856,6 +816,7 @@ 2170 return 0; 2171 #endif 2172 } 2173+#endif 2174 2175 protected int 2176 file_clear_closexec(int fd) { 2177diff -u libmagic.orig/magic.c libmagic/magic.c 2178--- libmagic.orig/magic.c 2022-09-13 20:37:57.000000000 +0200 2179+++ libmagic/magic.c 2023-10-25 17:56:17.069962152 +0200 2180@@ -25,11 +25,6 @@ 2181 * SUCH DAMAGE. 2182 */ 2183 2184-#ifdef WIN32 2185-#include <windows.h> 2186-#include <shlwapi.h> 2187-#endif 2188- 2189 #include "file.h" 2190 2191 #ifndef lint 2192@@ -39,7 +34,9 @@ 2193 #include "magic.h" 2194 2195 #include <stdlib.h> 2196+#ifdef HAVE_UNISTD_H 2197 #include <unistd.h> 2198+#endif 2199 #include <string.h> 2200 #ifdef QUICK 2201 #include <sys/mman.h> 2202@@ -69,200 +66,18 @@ 2203 #endif 2204 #endif 2205 2206-private void close_and_restore(const struct magic_set *, const char *, int, 2207- const struct stat *); 2208-private int unreadable_info(struct magic_set *, mode_t, const char *); 2209-private const char* get_default_magic(void); 2210-#ifndef COMPILE_ONLY 2211-private const char *file_or_fd(struct magic_set *, const char *, int); 2212+#ifdef PHP_WIN32 2213+# undef S_IFLNK 2214+# undef S_IFIFO 2215 #endif 2216 2217+private int unreadable_info(struct magic_set *, mode_t, const char *); 2218+private const char *file_or_stream(struct magic_set *, const char *, php_stream *); 2219+ 2220 #ifndef STDIN_FILENO 2221 #define STDIN_FILENO 0 2222 #endif 2223 2224-#ifdef WIN32 2225-/* HINSTANCE of this shared library. Needed for get_default_magic() */ 2226-static HINSTANCE _w32_dll_instance = NULL; 2227- 2228-static void 2229-_w32_append_path(char **hmagicpath, const char *fmt, ...) 2230-{ 2231- char *tmppath; 2232- char *newpath; 2233- va_list ap; 2234- 2235- va_start(ap, fmt); 2236- if (vasprintf(&tmppath, fmt, ap) < 0) { 2237- va_end(ap); 2238- return; 2239- } 2240- va_end(ap); 2241- 2242- if (access(tmppath, R_OK) == -1) 2243- goto out; 2244- 2245- if (*hmagicpath == NULL) { 2246- *hmagicpath = tmppath; 2247- return; 2248- } 2249- 2250- if (asprintf(&newpath, "%s%c%s", *hmagicpath, PATHSEP, tmppath) < 0) 2251- goto out; 2252- 2253- free(*hmagicpath); 2254- free(tmppath); 2255- *hmagicpath = newpath; 2256- return; 2257-out: 2258- free(tmppath); 2259-} 2260- 2261-static void 2262-_w32_get_magic_relative_to(char **hmagicpath, HINSTANCE module) 2263-{ 2264- static const char *trypaths[] = { 2265- "%s/share/misc/magic.mgc", 2266- "%s/magic.mgc", 2267- }; 2268- LPSTR dllpath; 2269- size_t sp; 2270- 2271- dllpath = calloc(MAX_PATH + 1, sizeof(*dllpath)); 2272- 2273- if (!GetModuleFileNameA(module, dllpath, MAX_PATH)) 2274- goto out; 2275- 2276- PathRemoveFileSpecA(dllpath); 2277- 2278- if (module) { 2279- char exepath[MAX_PATH]; 2280- GetModuleFileNameA(NULL, exepath, MAX_PATH); 2281- PathRemoveFileSpecA(exepath); 2282- if (stricmp(exepath, dllpath) == 0) 2283- goto out; 2284- } 2285- 2286- sp = strlen(dllpath); 2287- if (sp > 3 && stricmp(&dllpath[sp - 3], "bin") == 0) { 2288- _w32_append_path(hmagicpath, 2289- "%s/../share/misc/magic.mgc", dllpath); 2290- goto out; 2291- } 2292- 2293- for (sp = 0; sp < __arraycount(trypaths); sp++) 2294- _w32_append_path(hmagicpath, trypaths[sp], dllpath); 2295-out: 2296- free(dllpath); 2297-} 2298- 2299-#ifndef BUILD_AS_WINDOWS_STATIC_LIBARAY 2300-/* Placate GCC by offering a sacrificial previous prototype */ 2301-BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID); 2302- 2303-BOOL WINAPI 2304-DllMain(HINSTANCE hinstDLL, DWORD fdwReason, 2305- LPVOID lpvReserved __attribute__((__unused__))) 2306-{ 2307- if (fdwReason == DLL_PROCESS_ATTACH) 2308- _w32_dll_instance = hinstDLL; 2309- return 1; 2310-} 2311-#endif 2312-#endif 2313- 2314-private const char * 2315-get_default_magic(void) 2316-{ 2317- static const char hmagic[] = "/.magic/magic.mgc"; 2318- static char *default_magic; 2319- char *home, *hmagicpath; 2320- 2321-#ifndef WIN32 2322- struct stat st; 2323- 2324- if (default_magic) { 2325- free(default_magic); 2326- default_magic = NULL; 2327- } 2328- if ((home = getenv("HOME")) == NULL) 2329- return MAGIC; 2330- 2331- if (asprintf(&hmagicpath, "%s/.magic.mgc", home) < 0) 2332- return MAGIC; 2333- if (stat(hmagicpath, &st) == -1) { 2334- free(hmagicpath); 2335- if (asprintf(&hmagicpath, "%s/.magic", home) < 0) 2336- return MAGIC; 2337- if (stat(hmagicpath, &st) == -1) 2338- goto out; 2339- if (S_ISDIR(st.st_mode)) { 2340- free(hmagicpath); 2341- if (asprintf(&hmagicpath, "%s/%s", home, hmagic) < 0) 2342- return MAGIC; 2343- if (access(hmagicpath, R_OK) == -1) 2344- goto out; 2345- } 2346- } 2347- 2348- if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0) 2349- goto out; 2350- free(hmagicpath); 2351- return default_magic; 2352-out: 2353- default_magic = NULL; 2354- free(hmagicpath); 2355- return MAGIC; 2356-#else 2357- hmagicpath = NULL; 2358- 2359- if (default_magic) { 2360- free(default_magic); 2361- default_magic = NULL; 2362- } 2363- 2364- /* Before anything else, try to get a magic file from user HOME */ 2365- if ((home = getenv("HOME")) != NULL) 2366- _w32_append_path(&hmagicpath, "%s%s", home, hmagic); 2367- 2368- /* First, try to get a magic file from user-application data */ 2369- if ((home = getenv("LOCALAPPDATA")) != NULL) 2370- _w32_append_path(&hmagicpath, "%s%s", home, hmagic); 2371- 2372- /* Second, try to get a magic file from the user profile data */ 2373- if ((home = getenv("USERPROFILE")) != NULL) 2374- _w32_append_path(&hmagicpath, 2375- "%s/Local Settings/Application Data%s", home, hmagic); 2376- 2377- /* Third, try to get a magic file from Common Files */ 2378- if ((home = getenv("COMMONPROGRAMFILES")) != NULL) 2379- _w32_append_path(&hmagicpath, "%s%s", home, hmagic); 2380- 2381- /* Fourth, try to get magic file relative to exe location */ 2382- _w32_get_magic_relative_to(&hmagicpath, NULL); 2383- 2384- /* Fifth, try to get magic file relative to dll location */ 2385- _w32_get_magic_relative_to(&hmagicpath, _w32_dll_instance); 2386- 2387- /* Avoid MAGIC constant - it likely points to a file within MSys tree */ 2388- default_magic = hmagicpath; 2389- return default_magic; 2390-#endif 2391-} 2392- 2393-public const char * 2394-magic_getpath(const char *magicfile, int action) 2395-{ 2396- if (magicfile != NULL) 2397- return magicfile; 2398- 2399- magicfile = getenv("MAGIC"); 2400- if (magicfile != NULL) 2401- return magicfile; 2402- 2403- return action == FILE_LOAD ? get_default_magic() : MAGIC; 2404-} 2405- 2406 public struct magic_set * 2407 magic_open(int flags) 2408 { 2409@@ -321,21 +136,6 @@ 2410 return file_apprentice(ms, magicfile, FILE_LOAD); 2411 } 2412 2413-#ifndef COMPILE_ONLY 2414-/* 2415- * Install a set of compiled magic buffers. 2416- */ 2417-public int 2418-magic_load_buffers(struct magic_set *ms, void **bufs, size_t *sizes, 2419- size_t nbufs) 2420-{ 2421- if (ms == NULL) 2422- return -1; 2423- return buffer_apprentice(ms, RCAST(struct magic **, bufs), 2424- sizes, nbufs); 2425-} 2426-#endif 2427- 2428 public int 2429 magic_compile(struct magic_set *ms, const char *magicfile) 2430 { 2431@@ -360,39 +160,6 @@ 2432 return file_apprentice(ms, magicfile, FILE_LIST); 2433 } 2434 2435-private void 2436-close_and_restore(const struct magic_set *ms, const char *name, int fd, 2437- const struct stat *sb) 2438-{ 2439- if (fd == STDIN_FILENO || name == NULL) 2440- return; 2441- (void) close(fd); 2442- 2443- if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) { 2444- /* 2445- * Try to restore access, modification times if read it. 2446- * This is really *bad* because it will modify the status 2447- * time of the file... And of course this will affect 2448- * backup programs 2449- */ 2450-#ifdef HAVE_UTIMES 2451- struct timeval utsbuf[2]; 2452- (void)memset(utsbuf, 0, sizeof(utsbuf)); 2453- utsbuf[0].tv_sec = sb->st_atime; 2454- utsbuf[1].tv_sec = sb->st_mtime; 2455- 2456- (void) utimes(name, utsbuf); /* don't care if loses */ 2457-#elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H) 2458- struct utimbuf utbuf; 2459- 2460- (void)memset(&utbuf, 0, sizeof(utbuf)); 2461- utbuf.actime = sb->st_atime; 2462- utbuf.modtime = sb->st_mtime; 2463- (void) utime(name, &utbuf); /* don't care if loses */ 2464-#endif 2465- } 2466-} 2467- 2468 #ifndef COMPILE_ONLY 2469 2470 /* 2471@@ -403,7 +170,7 @@ 2472 { 2473 if (ms == NULL) 2474 return NULL; 2475- return file_or_fd(ms, NULL, fd); 2476+ return file_or_stream(ms, NULL, NULL); 2477 } 2478 2479 /* 2480@@ -414,19 +181,25 @@ 2481 { 2482 if (ms == NULL) 2483 return NULL; 2484- return file_or_fd(ms, inname, STDIN_FILENO); 2485+ return file_or_stream(ms, inname, NULL); 2486+} 2487+ 2488+public const char * 2489+magic_stream(struct magic_set *ms, php_stream *stream) 2490+{ 2491+ if (ms == NULL) 2492+ return NULL; 2493+ return file_or_stream(ms, NULL, stream); 2494 } 2495 2496 private const char * 2497-file_or_fd(struct magic_set *ms, const char *inname, int fd) 2498+file_or_stream(struct magic_set *ms, const char *inname, php_stream *stream) 2499 { 2500 int rv = -1; 2501 unsigned char *buf; 2502- struct stat sb; 2503+ zend_stat_t sb = {0}; 2504 ssize_t nbytes = 0; /* number of bytes read from a datafile */ 2505- int ispipe = 0; 2506- int okstat = 0; 2507- off_t pos = CAST(off_t, -1); 2508+ int no_in_stream = 0; 2509 2510 if (file_reset(ms, 1) == -1) 2511 goto out; 2512@@ -436,7 +209,7 @@ 2513 * some overlapping space for matches near EOF 2514 */ 2515 #define SLOP (1 + sizeof(union VALUETYPE)) 2516- if ((buf = CAST(unsigned char *, malloc(ms->bytes_max + SLOP))) == NULL) 2517+ if ((buf = CAST(unsigned char *, emalloc(ms->bytes_max + SLOP))) == NULL) 2518 return NULL; 2519 2520 switch (file_fsmagic(ms, inname, &sb)) { 2521@@ -449,96 +222,46 @@ 2522 goto done; 2523 } 2524 2525-#ifdef WIN32 2526- /* Place stdin in binary mode, so EOF (Ctrl+Z) doesn't stop early. */ 2527- if (fd == STDIN_FILENO) 2528- _setmode(STDIN_FILENO, O_BINARY); 2529-#endif 2530- if (inname != NULL) { 2531- int flags = O_RDONLY|O_BINARY|O_NONBLOCK|O_CLOEXEC; 2532- errno = 0; 2533- if ((fd = open(inname, flags)) < 0) { 2534- okstat = stat(inname, &sb) == 0; 2535-#ifdef WIN32 2536- /* 2537- * Can't stat, can't open. It may have been opened in 2538- * fsmagic, so if the user doesn't have read permission, 2539- * allow it to say so; otherwise an error was probably 2540- * displayed in fsmagic. 2541- */ 2542- if (!okstat && errno == EACCES) { 2543- sb.st_mode = S_IFBLK; 2544- okstat = 1; 2545- } 2546-#endif 2547- if (okstat && 2548- unreadable_info(ms, sb.st_mode, inname) == -1) 2549+ errno = 0; 2550+ 2551+ if (inname && !stream) { 2552+ no_in_stream = 1; 2553+ stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS, NULL); 2554+ if (!stream) { 2555+ if (unreadable_info(ms, sb.st_mode, inname) == -1) 2556 goto done; 2557- rv = 0; 2558+ rv = -1; 2559 goto done; 2560 } 2561-#if O_CLOEXEC == 0 && defined(F_SETFD) 2562- (void)fcntl(fd, F_SETFD, FD_CLOEXEC); 2563-#endif 2564 } 2565 2566- if (fd != -1) { 2567- okstat = fstat(fd, &sb) == 0; 2568- if (okstat && S_ISFIFO(sb.st_mode)) 2569- ispipe = 1; 2570- if (inname == NULL) 2571- pos = lseek(fd, CAST(off_t, 0), SEEK_CUR); 2572+ php_stream_statbuf ssb; 2573+ if (php_stream_stat(stream, &ssb) < 0) { 2574+ if (ms->flags & MAGIC_ERROR) { 2575+ file_error(ms, errno, "cannot stat `%s'", inname); 2576+ rv = -1; 2577+ goto done; 2578+ } 2579 } 2580+ memcpy(&sb, &ssb.sb, sizeof(zend_stat_t)); 2581 2582 /* 2583 * try looking at the first ms->bytes_max bytes 2584 */ 2585- if (ispipe) { 2586- if (fd != -1) { 2587- ssize_t r = 0; 2588- 2589- while ((r = sread(fd, RCAST(void *, &buf[nbytes]), 2590- CAST(size_t, ms->bytes_max - nbytes), 1)) > 0) { 2591- nbytes += r; 2592- if (r < PIPE_BUF) break; 2593- } 2594- } 2595- 2596- if (nbytes == 0 && inname) { 2597- /* We can not read it, but we were able to stat it. */ 2598- if (unreadable_info(ms, sb.st_mode, inname) == -1) 2599- goto done; 2600- rv = 0; 2601- goto done; 2602- } 2603- 2604- } else if (fd != -1) { 2605- /* Windows refuses to read from a big console buffer. */ 2606- size_t howmany = 2607-#ifdef WIN32 2608- _isatty(fd) ? 8 * 1024 : 2609-#endif 2610- ms->bytes_max; 2611- if ((nbytes = read(fd, RCAST(void *, buf), howmany)) == -1) { 2612- if (inname == NULL && fd != STDIN_FILENO) 2613- file_error(ms, errno, "cannot read fd %d", fd); 2614- else 2615- file_error(ms, errno, "cannot read `%s'", 2616- inname == NULL ? "/dev/stdin" : inname); 2617- goto done; 2618- } 2619+ if ((nbytes = php_stream_read(stream, (char *)buf, ms->bytes_max - nbytes)) < 0) { 2620+ file_error(ms, errno, "cannot read `%s'", inname); 2621+ goto done; 2622 } 2623 2624 (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */ 2625- if (file_buffer(ms, fd, okstat ? &sb : NULL, inname, buf, CAST(size_t, nbytes)) == -1) 2626+ if (file_buffer(ms, stream, &sb, inname, buf, CAST(size_t, nbytes)) == -1) 2627 goto done; 2628 rv = 0; 2629 done: 2630- free(buf); 2631- if (fd != -1) { 2632- if (pos != CAST(off_t, -1)) 2633- (void)lseek(fd, pos, SEEK_SET); 2634- close_and_restore(ms, inname, fd, &sb); 2635+ efree(buf); 2636+ 2637+ if (no_in_stream && stream) { 2638+ php_stream_close(stream); 2639 } 2640 out: 2641 return rv == 0 ? file_getbuffer(ms) : NULL; 2642@@ -556,7 +279,7 @@ 2643 * The main work is done here! 2644 * We have the file name and/or the data buffer to be identified. 2645 */ 2646- if (file_buffer(ms, -1, NULL, NULL, buf, nb) == -1) { 2647+ if (file_buffer(ms, NULL, NULL, NULL, buf, nb) == -1) { 2648 return NULL; 2649 } 2650 return file_getbuffer(ms); 2651diff -u libmagic.orig/magic.h libmagic/magic.h 2652--- libmagic.orig/magic.h 2024-02-13 21:14:59.340250330 +0100 2653+++ libmagic/magic.h 2023-10-25 17:56:17.069962152 +0200 2654@@ -126,6 +126,7 @@ 2655 2656 const char *magic_getpath(const char *, int); 2657 const char *magic_file(magic_t, const char *); 2658+const char *magic_stream(magic_t, php_stream *); 2659 const char *magic_descriptor(magic_t, int); 2660 const char *magic_buffer(magic_t, const void *, size_t); 2661 2662diff -u libmagic.orig/print.c libmagic/print.c 2663--- libmagic.orig/print.c 2022-09-13 20:38:34.000000000 +0200 2664+++ libmagic/print.c 2023-10-25 17:56:17.069962152 +0200 2665@@ -73,7 +73,7 @@ 2666 if (m->mask_op & FILE_OPINVERSE) 2667 (void) fputc('~', stderr); 2668 2669- if (IS_STRING(m->type)) { 2670+ if (IS_LIBMAGIC_STRING(m->type)) { 2671 if (m->str_flags) { 2672 (void) fputc('/', stderr); 2673 if (m->str_flags & STRING_COMPACT_WHITESPACE) 2674@@ -246,18 +246,18 @@ 2675 file_magwarn(struct magic_set *ms, const char *f, ...) 2676 { 2677 va_list va; 2678+ char *expanded_format = NULL; 2679+ int expanded_len; 2680 2681- /* cuz we use stdout for most, stderr here */ 2682- (void) fflush(stdout); 2683- 2684- if (ms->file) 2685- (void) fprintf(stderr, "%s, %lu: ", ms->file, 2686- CAST(unsigned long, ms->line)); 2687- (void) fprintf(stderr, "Warning: "); 2688 va_start(va, f); 2689- (void) vfprintf(stderr, f, va); 2690+ expanded_len = vasprintf(&expanded_format, f, va); 2691 va_end(va); 2692- (void) fputc('\n', stderr); 2693+ 2694+ if (expanded_len >= 0 && expanded_format) { 2695+ php_error_docref(NULL, E_WARNING, "%s", expanded_format); 2696+ 2697+ free(expanded_format); 2698+ } 2699 } 2700 2701 protected const char * 2702@@ -285,13 +285,13 @@ 2703 } 2704 2705 if (flags & FILE_T_LOCAL) { 2706- tm = localtime_r(&t, &tmz); 2707+ tm = php_localtime_r(&t, &tmz); 2708 } else { 2709- tm = gmtime_r(&t, &tmz); 2710+ tm = php_gmtime_r(&t, &tmz); 2711 } 2712 if (tm == NULL) 2713 goto out; 2714- pp = asctime_r(tm, buf); 2715+ pp = php_asctime_r(tm, buf); 2716 2717 if (pp == NULL) 2718 goto out; 2719diff -u libmagic.orig/readcdf.c libmagic/readcdf.c 2720--- libmagic.orig/readcdf.c 2022-09-13 20:38:40.000000000 +0200 2721+++ libmagic/readcdf.c 2023-10-25 17:56:17.069962152 +0200 2722@@ -31,7 +31,9 @@ 2723 2724 #include <assert.h> 2725 #include <stdlib.h> 2726+#ifdef HAVE_UNISTD_H 2727 #include <unistd.h> 2728+#endif 2729 #include <string.h> 2730 #include <time.h> 2731 #include <ctype.h> 2732@@ -100,10 +102,6 @@ 2733 if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1]) 2734 return cv[i].mime; 2735 } 2736-#ifdef CDF_DEBUG 2737- fprintf(stderr, "unknown mime %" PRIx64 ", %" PRIx64 "\n", clsid[0], 2738- clsid[1]); 2739-#endif 2740 return NULL; 2741 } 2742 2743@@ -112,35 +110,24 @@ 2744 { 2745 size_t i; 2746 const char *rv = NULL; 2747-#ifdef USE_C_LOCALE 2748- locale_t old_lc_ctype, c_lc_ctype; 2749+ char *vbuf_lower; 2750 2751- c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0); 2752- assert(c_lc_ctype != NULL); 2753- old_lc_ctype = uselocale(c_lc_ctype); 2754- assert(old_lc_ctype != NULL); 2755-#else 2756- char *old_lc_ctype = setlocale(LC_CTYPE, NULL); 2757- assert(old_lc_ctype != NULL); 2758- old_lc_ctype = strdup(old_lc_ctype); 2759- assert(old_lc_ctype != NULL); 2760- (void)setlocale(LC_CTYPE, "C"); 2761-#endif 2762- for (i = 0; nv[i].pattern != NULL; i++) 2763- if (strcasestr(vbuf, nv[i].pattern) != NULL) { 2764+ vbuf_lower = zend_str_tolower_dup(vbuf, strlen(vbuf)); 2765+ for (i = 0; nv[i].pattern != NULL; i++) { 2766+ char *pattern_lower; 2767+ int found; 2768+ 2769+ pattern_lower = zend_str_tolower_dup(nv[i].pattern, strlen(nv[i].pattern)); 2770+ found = (strstr(vbuf_lower, pattern_lower) != NULL); 2771+ efree(pattern_lower); 2772+ 2773+ if (found) { 2774 rv = nv[i].mime; 2775 break; 2776 } 2777-#ifdef CDF_DEBUG 2778- fprintf(stderr, "unknown app %s\n", vbuf); 2779-#endif 2780-#ifdef USE_C_LOCALE 2781- (void)uselocale(old_lc_ctype); 2782- freelocale(c_lc_ctype); 2783-#else 2784- (void)setlocale(LC_CTYPE, old_lc_ctype); 2785- free(old_lc_ctype); 2786-#endif 2787+ } 2788+ 2789+ efree(vbuf_lower); 2790 return rv; 2791 } 2792 2793@@ -156,6 +143,8 @@ 2794 const char *s, *e; 2795 int len; 2796 2797+ memset(&ts, 0, sizeof(ts)); 2798+ 2799 if (!NOTMIME(ms) && root_storage) 2800 str = cdf_clsid_to_mime(root_storage->d_storage_uuid, 2801 clsid2mime); 2802@@ -282,10 +271,10 @@ 2803 if (file_printf(ms, "%s%s", 2804 cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name), 2805 i == cat->cat_num - 1 ? "]" : ", ") == -1) { 2806- free(cat); 2807+ efree(cat); 2808 return -1; 2809 } 2810- free(cat); 2811+ efree(cat); 2812 } else if (ms->flags & MAGIC_MIME_TYPE) { 2813 if (file_printf(ms, "application/CDFV2") == -1) 2814 return -1; 2815@@ -346,7 +335,7 @@ 2816 } 2817 2818 m = cdf_file_property_info(ms, info, count, root_storage); 2819- free(info); 2820+ efree(info); 2821 2822 return m == -1 ? -2 : m; 2823 } 2824@@ -656,11 +645,11 @@ 2825 cdf_zero_stream(&scn); 2826 cdf_zero_stream(&sst); 2827 out3: 2828- free(dir.dir_tab); 2829+ efree(dir.dir_tab); 2830 out2: 2831- free(ssat.sat_tab); 2832+ efree(ssat.sat_tab); 2833 out1: 2834- free(sat.sat_tab); 2835+ efree(sat.sat_tab); 2836 out0: 2837 /* If we handled it already, return */ 2838 if (i != -1) 2839diff -u libmagic.orig/softmagic.c libmagic/softmagic.c 2840--- libmagic.orig/softmagic.c 2022-09-13 20:46:07.000000000 +0200 2841+++ libmagic/softmagic.c 2023-10-25 17:56:17.069962152 +0200 2842@@ -43,7 +43,7 @@ 2843 #include <time.h> 2844 #include "der.h" 2845 2846-private int match(struct magic_set *, struct magic *, file_regex_t **, size_t, 2847+private int match(struct magic_set *, struct magic *, size_t, 2848 const struct buffer *, size_t, int, int, int, uint16_t *, 2849 uint16_t *, int *, int *, int *, int *); 2850 private int mget(struct magic_set *, struct magic *, const struct buffer *, 2851@@ -52,7 +52,7 @@ 2852 uint16_t *, int *, int *, int *, int *); 2853 private int msetoffset(struct magic_set *, struct magic *, struct buffer *, 2854 const struct buffer *, size_t, unsigned int); 2855-private int magiccheck(struct magic_set *, struct magic *, file_regex_t **); 2856+private int magiccheck(struct magic_set *, struct magic *); 2857 private int mprint(struct magic_set *, struct magic *); 2858 private int moffset(struct magic_set *, struct magic *, const struct buffer *, 2859 int32_t *); 2860@@ -131,7 +131,7 @@ 2861 } 2862 2863 for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) { 2864- int ret = match(ms, ml->magic, ml->magic_rxcomp, ml->nmagic, b, 2865+ int ret = match(ms, ml->magic, ml->nmagic, b, 2866 0, mode, text, 0, indir_count, name_count, 2867 &printed_something, &need_separator, NULL, NULL); 2868 switch (ret) { 2869@@ -150,8 +150,8 @@ 2870 return rv; 2871 } 2872 2873-#define FILE_FMTDEBUG 2874-#ifdef FILE_FMTDEBUG 2875+ 2876+#if defined(FILE_FMTDEBUG) && defined(HAVE_FMTCHECK) 2877 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__) 2878 2879 private const char * __attribute__((__format_arg__(3))) 2880@@ -170,10 +170,14 @@ 2881 " with `%s'", file, line, desc, def); 2882 return ptr; 2883 } 2884-#else 2885+#elif defined(HAVE_FMTCHECK) 2886 #define F(a, b, c) fmtcheck((b), (c)) 2887+#else 2888+#define F(a, b, c) ((b)) 2889 #endif 2890 2891+/* NOTE this function has been kept an the state of 5.39 for BC. Observe 2892+ * further as the upgrade to 5.41 or above goes. */ 2893 /* 2894 * Go through the whole list, stopping if you find a match. Process all 2895 * the continuations of that match before returning. 2896@@ -202,7 +206,7 @@ 2897 * so that higher-level continuations are processed. 2898 */ 2899 private int 2900-match(struct magic_set *ms, struct magic *magic, file_regex_t **magic_rxcomp, 2901+match(struct magic_set *ms, struct magic *magic, 2902 size_t nmagic, const struct buffer *b, size_t offset, int mode, int text, 2903 int flip, uint16_t *indir_count, uint16_t *name_count, 2904 int *printed_something, int *need_separator, int *returnval, 2905@@ -232,10 +236,9 @@ 2906 for (magindex = 0; magindex < nmagic; magindex++) { 2907 int flush = 0; 2908 struct magic *m = &magic[magindex]; 2909- file_regex_t **m_rxcomp = &magic_rxcomp[magindex]; 2910 2911 if (m->type != FILE_NAME) 2912- if ((IS_STRING(m->type) && 2913+ if ((IS_LIBMAGIC_STRING(m->type) && 2914 #define FLT (STRING_BINTEST | STRING_TEXTTEST) 2915 ((text && (m->str_flags & FLT) == STRING_BINTEST) || 2916 (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) || 2917@@ -270,7 +273,7 @@ 2918 *returnval = 1; 2919 } 2920 2921- switch (magiccheck(ms, m, m_rxcomp)) { 2922+ switch (magiccheck(ms, m)) { 2923 case -1: 2924 return -1; 2925 case 0: 2926@@ -331,7 +334,6 @@ 2927 while (magindex + 1 < nmagic && 2928 magic[magindex + 1].cont_level != 0) { 2929 m = &magic[++magindex]; 2930- m_rxcomp = &magic_rxcomp[magindex]; 2931 ms->line = m->lineno; /* for messages */ 2932 2933 if (cont_level < m->cont_level) 2934@@ -385,7 +387,7 @@ 2935 break; 2936 } 2937 2938- switch (flush ? 1 : magiccheck(ms, m, m_rxcomp)) { 2939+ switch (flush ? 1 : magiccheck(ms, m)) { 2940 case -1: 2941 return -1; 2942 case 0: 2943@@ -484,19 +486,25 @@ 2944 private int 2945 check_fmt(struct magic_set *ms, const char *fmt) 2946 { 2947- file_regex_t rx; 2948- int rc, rv = -1; 2949- const char* pat = "%[-0-9\\.]*s"; 2950+ pcre_cache_entry *pce; 2951+ int rv = -1; 2952+ zend_string *pattern; 2953 2954 if (strchr(fmt, '%') == NULL) 2955 return 0; 2956 2957- rc = file_regcomp(ms, &rx, pat, REG_EXTENDED|REG_NOSUB); 2958- if (rc == 0) { 2959- rc = file_regexec(ms, &rx, fmt, 0, 0, 0); 2960- rv = !rc; 2961+ pattern = ZSTR_INIT_LITERAL("~%[-0-9\\.]*s~", 0); 2962+ if ((pce = pcre_get_compiled_regex_cache_ex(pattern, 0)) == NULL) { 2963+ rv = -1; 2964+ } else { 2965+ pcre2_code *re = php_pcre_pce_re(pce); 2966+ pcre2_match_data *match_data = php_pcre_create_match_data(0, re); 2967+ if (match_data) { 2968+ rv = pcre2_match(re, (PCRE2_SPTR)fmt, strlen(fmt), 0, 0, match_data, php_pcre_mctx()) > 0; 2969+ php_pcre_free_match_data(match_data); 2970+ } 2971 } 2972- file_regfree(&rx); 2973+ zend_string_release(pattern); 2974 return rv; 2975 } 2976 2977@@ -514,7 +522,7 @@ 2978 2979 for (len = 0; len < n && str[len]; len++) 2980 continue; 2981- if ((copy = CAST(char *, malloc(len + 1))) == NULL) 2982+ if ((copy = CAST(char *, emalloc(len + 1))) == NULL) 2983 return NULL; 2984 (void)memcpy(copy, str, len); 2985 copy[len] = '\0'; 2986@@ -764,7 +772,7 @@ 2987 char *cp, *scp; 2988 int rval; 2989 2990- cp = strndup(RCAST(const char *, ms->search.s), 2991+ cp = estrndup(RCAST(const char *, ms->search.s), 2992 ms->search.rm_len); 2993 if (cp == NULL) { 2994 file_oomem(ms, ms->search.rm_len); 2995@@ -774,7 +782,7 @@ 2996 2997 rval = file_printf(ms, F(ms, desc, "%s"), file_printable(ms, 2998 sbuf, sizeof(sbuf), scp, ms->search.rm_len)); 2999- free(cp); 3000+ efree(cp); 3001 3002 if (rval == -1) 3003 return -1; 3004@@ -1544,7 +1552,7 @@ 3005 size_t len; 3006 *c = ms->c; 3007 len = c->len * sizeof(*c->li); 3008- ms->c.li = CAST(struct level_info *, malloc(len)); 3009+ ms->c.li = CAST(struct level_info *, emalloc(len)); 3010 if (ms->c.li == NULL) { 3011 ms->c = *c; 3012 return -1; 3013@@ -1556,7 +1564,7 @@ 3014 private void 3015 restore_cont(struct magic_set *ms, struct cont *c) 3016 { 3017- free(ms->c.li); 3018+ efree(ms->c.li); 3019 ms->c = *c; 3020 } 3021 3022@@ -1860,7 +1868,7 @@ 3023 for (mlp = ms->mlist[0]->next; mlp != ms->mlist[0]; 3024 mlp = mlp->next) 3025 { 3026- if ((rv = match(ms, mlp->magic, mlp->magic_rxcomp, 3027+ if ((rv = match(ms, mlp->magic, 3028 mlp->nmagic, &bb, 0, BINTEST, text, 0, indir_count, 3029 name_count, printed_something, need_separator, 3030 NULL, NULL)) != 0) 3031@@ -1878,15 +1886,15 @@ 3032 if ((ms->flags & MAGIC_NODESC) == 0 && 3033 file_printf(ms, F(ms, m->desc, "%u"), offset) == -1) 3034 { 3035- free(rbuf); 3036+ if (rbuf) efree(rbuf); 3037 return -1; 3038 } 3039 if (file_printf(ms, "%s", rbuf) == -1) { 3040- free(rbuf); 3041+ if (rbuf) efree(rbuf); 3042 return -1; 3043 } 3044 } 3045- free(rbuf); 3046+ if (rbuf) efree(rbuf); 3047 return rv; 3048 3049 case FILE_USE: 3050@@ -1913,7 +1921,7 @@ 3051 nfound_match = 0; 3052 (*name_count)++; 3053 eoffset = ms->eoffset; 3054- rv = match(ms, ml.magic, ml.magic_rxcomp, ml.nmagic, b, 3055+ rv = match(ms, ml.magic, ml.nmagic, b, 3056 offset + o, mode, text, flip, indir_count, name_count, 3057 printed_something, need_separator, returnval, 3058 &nfound_match); 3059@@ -1992,11 +2000,13 @@ 3060 } 3061 else if ((flags & STRING_COMPACT_WHITESPACE) && 3062 isspace(*a)) { 3063+ /* XXX Dirty. The data and the pattern is what is causing this. 3064+ Revert _i for the next port and see if it still matters. */ 3065+ uint32_t _i = 0; 3066 a++; 3067- if (isspace(*b)) { 3068- b++; 3069+ if (isspace(*b++)) { 3070 if (!isspace(*a)) 3071- while (b < eb && isspace(*b)) 3072+ while (EXPECTED(_i++ < 2048) && b < eb && isspace(*b)) 3073 b++; 3074 } 3075 else { 3076@@ -2036,29 +2046,8 @@ 3077 return file_strncmp(a, b, len, maxlen, flags); 3078 } 3079 3080-private file_regex_t * 3081-alloc_regex(struct magic_set *ms, struct magic *m) 3082-{ 3083- int rc; 3084- file_regex_t *rx = CAST(file_regex_t *, malloc(sizeof(*rx))); 3085- 3086- if (rx == NULL) { 3087- file_error(ms, errno, "can't allocate %" SIZE_T_FORMAT 3088- "u bytes", sizeof(*rx)); 3089- return NULL; 3090- } 3091- 3092- rc = file_regcomp(ms, rx, m->value.s, REG_EXTENDED | REG_NEWLINE | 3093- ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0)); 3094- if (rc == 0) 3095- return rx; 3096- 3097- free(rx); 3098- return NULL; 3099-} 3100- 3101 private int 3102-magiccheck(struct magic_set *ms, struct magic *m, file_regex_t **m_cache) 3103+magiccheck(struct magic_set *ms, struct magic *m) 3104 { 3105 uint64_t l = m->value.q; 3106 uint64_t v; 3107@@ -2218,8 +2207,8 @@ 3108 idx = m->str_range + slen; 3109 if (m->str_range == 0 || ms->search.s_len < idx) 3110 idx = ms->search.s_len; 3111- found = CAST(const char *, memmem(ms->search.s, idx, 3112- m->value.s, slen)); 3113+ found = CAST(const char *, php_memnstr(ms->search.s, 3114+ m->value.s, slen, ms->search.s + idx)); 3115 if (!found) { 3116 v = 1; 3117 break; 3118@@ -2248,55 +2237,76 @@ 3119 break; 3120 } 3121 case FILE_REGEX: { 3122- int rc; 3123- file_regex_t *rx = *m_cache; 3124- const char *search; 3125- regmatch_t pmatch; 3126- size_t slen = ms->search.s_len; 3127- char *copy; 3128+ zend_string *pattern; 3129+ uint32_t options = 0; 3130+ pcre_cache_entry *pce; 3131 3132- if (ms->search.s == NULL) 3133- return 0; 3134+ options |= PCRE2_MULTILINE; 3135 3136- if (rx == NULL) { 3137- rx = *m_cache = alloc_regex(ms, m); 3138- if (rx == NULL) 3139- return -1; 3140- } 3141- l = 0; 3142- if (slen != 0) { 3143- copy = CAST(char *, malloc(slen)); 3144- if (copy == NULL) { 3145- file_error(ms, errno, 3146- "can't allocate %" SIZE_T_FORMAT "u bytes", 3147- slen); 3148- return -1; 3149- } 3150- memcpy(copy, ms->search.s, slen); 3151- copy[--slen] = '\0'; 3152- search = copy; 3153- } else { 3154- search = CCAST(char *, ""); 3155- copy = NULL; 3156+ if (m->str_flags & STRING_IGNORE_CASE) { 3157+ options |= PCRE2_CASELESS; 3158 } 3159- rc = file_regexec(ms, rx, RCAST(const char *, search), 3160- 1, &pmatch, 0); 3161- free(copy); 3162- switch (rc) { 3163- case 0: 3164- ms->search.s += CAST(int, pmatch.rm_so); 3165- ms->search.offset += CAST(size_t, pmatch.rm_so); 3166- ms->search.rm_len = CAST(size_t, 3167- pmatch.rm_eo - pmatch.rm_so); 3168- v = 0; 3169- break; 3170 3171- case REG_NOMATCH: 3172- v = 1; 3173- break; 3174+ pattern = convert_libmagic_pattern((char *)m->value.s, m->vallen, options); 3175 3176- default: 3177+ l = v = 0; 3178+ if ((pce = pcre_get_compiled_regex_cache(pattern)) == NULL) { 3179+ zend_string_release(pattern); 3180 return -1; 3181+ } else { 3182+ /* pce now contains the compiled regex */ 3183+ zval retval; 3184+ zval subpats; 3185+ zend_string *haystack; 3186+ 3187+ ZVAL_NULL(&retval); 3188+ ZVAL_NULL(&subpats); 3189+ 3190+ /* Cut the search len from haystack, equals to REG_STARTEND */ 3191+ haystack = zend_string_init(ms->search.s, ms->search.s_len, 0); 3192+ 3193+ /* match v = 0, no match v = 1 */ 3194+ php_pcre_match_impl(pce, haystack, &retval, &subpats, 0, 1, PREG_OFFSET_CAPTURE, 0); 3195+ /* Free haystack */ 3196+ zend_string_release(haystack); 3197+ 3198+ if (Z_LVAL(retval) < 0) { 3199+ zval_ptr_dtor(&subpats); 3200+ zend_string_release(pattern); 3201+ return -1; 3202+ } else if ((Z_LVAL(retval) > 0) && (Z_TYPE(subpats) == IS_ARRAY)) { 3203+ /* Need to fetch global match which equals pmatch[0] */ 3204+ zval *pzval; 3205+ HashTable *ht = Z_ARRVAL(subpats); 3206+ if ((pzval = zend_hash_index_find(ht, 0)) != NULL && Z_TYPE_P(pzval) == IS_ARRAY) { 3207+ /* If everything goes according to the master plan 3208+ tmpcopy now contains two elements: 3209+ 0 = the match 3210+ 1 = starting position of the match */ 3211+ zval *match, *offset; 3212+ if ((match = zend_hash_index_find(Z_ARRVAL_P(pzval), 0)) && 3213+ (offset = zend_hash_index_find(Z_ARRVAL_P(pzval), 1))) { 3214+ if (Z_TYPE_P(match) != IS_STRING && Z_TYPE_P(offset) != IS_LONG) { 3215+ goto error_out; 3216+ } 3217+ ms->search.s += Z_LVAL_P(offset); /* this is where the match starts */ 3218+ ms->search.offset += Z_LVAL_P(offset); /* this is where the match starts as size_t */ 3219+ ms->search.rm_len = Z_STRLEN_P(match) /* This is the length of the matched pattern */; 3220+ v = 0; 3221+ } else { 3222+ goto error_out; 3223+ } 3224+ } else { 3225+error_out: 3226+ zval_ptr_dtor(&subpats); 3227+ zend_string_release(pattern); 3228+ return -1; 3229+ } 3230+ } else { 3231+ v = 1; 3232+ } 3233+ zval_ptr_dtor(&subpats); 3234+ zend_string_release(pattern); 3235 } 3236 break; 3237 } 3238