Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ PHP NEWS
(timwolla)
. Fixed Uri\WhatWg\Url::parse() when resolving a relative URL
against a base URL with query or fragment. (timwolla)
. Fixed normalization of paths starting with two slashes for
Uri\Rfc3986\Uri. (timwolla)

25 Sep 2025, PHP 8.5.0RC1

Expand Down
2 changes: 1 addition & 1 deletion ext/uri/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ if test "$PHP_EXTERNAL_URIPARSER" = "no"; then
$URIPARSER_DIR/src/UriSetScheme.c $URIPARSER_DIR/src/UriSetUserInfo.c $URIPARSER_DIR/src/UriShorten.c $URIPARSER_DIR/src/UriVersion.c"
URI_CFLAGS="-DURI_STATIC_BUILD"
else
PKG_CHECK_MODULES([LIBURIPARSER], [liburiparser >= 0.9.9])
PKG_CHECK_MODULES([LIBURIPARSER], [liburiparser >= 0.9.10])
PHP_EVAL_LIBLINE([$LIBURIPARSER_LIBS], [URI_SHARED_LIBADD])
PHP_EVAL_INCLINE([$LIBURIPARSER_CFLAGS])
fi
Expand Down
6 changes: 3 additions & 3 deletions ext/uri/uriparser/include/uriparser/Uri.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ typedef struct URI_TYPE(HostDataStruct) {
URI_TYPE(TextRange) ipFuture; /**< IPvFuture address
@note
With non-<c>NULL</c> members in UriUriStructA.hostData context,
this text range's pointers must be <em>idential</em> to those
this text range's pointers must be <em>identical</em> to those
of UriUriStructA.hostText at all times. */
} URI_TYPE(HostData); /**< @copydoc UriHostDataStructA */

Expand Down Expand Up @@ -1420,7 +1420,7 @@ URI_PUBLIC UriBool URI_FUNC(IsWellFormedHostRegName)(const URI_CHAR * first, con
*
* @param first <b>IN</b>: Pointer to first character
* @param afterLast <b>IN</b>: Pointer to character after the last one still in
* @param hasHost <b>IN</b>: Wether the target %URI has a non-<c>NULL</c> host set or not
* @param hasHost <b>IN</b>: Whether the target %URI has a non-<c>NULL</c> host set or not
* @return <c>URI_TRUE</c> if non-<c>NULL</c> and well-formed, else <c>URI_FALSE</c>
*
* @see uriIsWellFormedFragmentA
Expand Down Expand Up @@ -2415,7 +2415,7 @@ URI_PUBLIC int URI_FUNC(SetUserInfoMm)(URI_TYPE(Uri) * uri,
* or even fully custom patches. As a result, the version string
* returned serves as nothing more than "based on that version",
* it does not guarantee equivalence to vanilla upstream releases
* or absence of additinal downstream patches.
* or absence of additional downstream patches.
* It is nothing more than "a hint" and MUST NEVER be used to
* make decisions on in application code at runtime.
*
Expand Down
80 changes: 60 additions & 20 deletions ext/uri/uriparser/include/uriparser/UriBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ typedef struct UriIp6Struct {
} UriIp6; /**< @copydoc UriIp6Struct */


struct UriMemoryManagerStruct; /* foward declaration to break loop */
struct UriMemoryManagerStruct; /* forward declaration to break loop */


/**
Expand Down Expand Up @@ -287,28 +287,34 @@ typedef enum UriResolutionOptionsEnum {


/**
* Wraps a memory manager backend that only provides malloc and free
* to make a complete memory manager ready to be used.
* Wraps a memory manager backend that only provides <c>malloc(3)</c> and
* <c>free(3)</c> to make a complete memory manager ready to be used.
*
* The core feature of this wrapper is that you don't need to implement
* realloc if you don't want to. The wrapped memory manager uses
* backend->malloc, memcpy, and backend->free and soieof(size_t) extra
* bytes per allocation to emulate fallback realloc for you.
* <c>realloc(3)</c> if you don't want to. The wrapped memory manager uses
* <c>backend-&gt;malloc</c>, <c>memcpy(3)</c>, and <c>backend-&gt;free</c> and
* (at least) <c>sizeof(size_t)</c> extra bytes per allocation to emulate
* fallback <c>realloc(3)</c> for you.
*
* memory->calloc is uriEmulateCalloc.
* memory->free uses backend->free and handles the size header.
* memory->malloc uses backend->malloc and adds a size header.
* memory->realloc uses memory->malloc, memcpy, and memory->free and reads
* the size header.
* memory->reallocarray is uriEmulateReallocarray.
* <ul>
* <li><c>memory-&gt;calloc</c> is <c>uriEmulateCalloc</c>.</li>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure about some of this &gt; escaping but if that is what upstream does...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This is a straight copy and paste from upstream's src/ and include/ directories (only ext/uri/uriparser/src/UriConfig.h is generated from ext/uri/uriparser/src/UriConfig.h.in).

* <li><c>memory-&gt;free</c> uses <c>backend-&gt;free</c>,
* and handles the size header.</li>
* <li><c>memory-&gt;malloc</c> uses <c>backend-&gt;malloc</c>,
* and adds a size header.</li>
* <li><c>memory-&gt;realloc</c> uses <c>memory-&gt;malloc</c>,
* <c>memcpy(3)</c> and <c>memory-&gt;free</c>,
* and reads the size header.</li>
* <li><c>memory-&gt;reallocarray</c> is <c>uriEmulateReallocarray</c>.</li>
* </ul>
*
* The internal workings behind memory->free, memory->malloc, and
* memory->realloc may change so the functions exposed by these function
* pointer sshould be consided internal and not public API.
* The internal workings behind <c>memory-&gt;free</c>, <c>memory-&gt;malloc</c>,
* and <c>memory-&gt;realloc</c> may change, and the functions exposed by these
* function pointers should be considered internal and not public API.
*
* @param memory <b>OUT</b>: Where to write the wrapped memory manager to
* @param backend <b>IN</b>: Memory manager to use as a backend
* @return Error code or 0 on success
* @return Error code or 0 on success
*
* @see uriEmulateCalloc
* @see uriEmulateReallocarray
Expand All @@ -321,7 +327,7 @@ URI_PUBLIC int uriCompleteMemoryManager(UriMemoryManager * memory,


/**
* Offers emulation of calloc(3) based on memory->malloc and memset.
* Offers emulation of calloc(3) based on memory-&gt;malloc and memset.
* See "man 3 calloc" as well.
*
* @param memory <b>IN</b>: Memory manager to use, should not be NULL
Expand All @@ -340,11 +346,11 @@ URI_PUBLIC void * uriEmulateCalloc(UriMemoryManager * memory,


/**
* Offers emulation of reallocarray(3) based on memory->realloc.
* Offers emulation of reallocarray(3) based on memory-&gt;realloc.
* See "man 3 reallocarray" as well.
*
* @param memory <b>IN</b>: Memory manager to use, should not be NULL
* @param ptr <b>IN</b>: Pointer allocated using memory->malloc/... or NULL
* @param ptr <b>IN</b>: Pointer allocated using memory-&gt;malloc/... or NULL
* @param nmemb <b>IN</b>: Number of elements to allocate
* @param size <b>IN</b>: Size in bytes per element
* @return Pointer to allocated memory or NULL
Expand All @@ -369,18 +375,52 @@ URI_PUBLIC void * uriEmulateReallocarray(UriMemoryManager * memory,
* 5. and frees that memory.
*
* It is recommended to compile with AddressSanitizer enabled
* to take full advantage of uriTestMemoryManager.
* to take full advantage of <c>uriTestMemoryManager</c>.
*
* For backwards-compatibility, <c>uriTestMemoryManager</c>
* does not challenge pointer alignment; please see
* <c>uriTestMemoryManagerEx</c> for that feature.
*
* @param memory <b>IN</b>: Memory manager to use, should not be NULL
* @return Error code or 0 on success
*
* @see uriEmulateCalloc
* @see uriEmulateReallocarray
* @see UriMemoryManager
* @see uriTestMemoryManagerEx
* @since 0.9.0
*/
URI_PUBLIC int uriTestMemoryManager(UriMemoryManager * memory);



/**
* Run multiple tests against a given memory manager.
* For example, one test
* 1. allocates a small amount of memory,
* 2. writes some magic bytes to it,
* 3. reallocates it,
* 4. checks that previous values are still present,
* 5. and frees that memory.
*
* It is recommended to compile with both AddressSanitizer and
* UndefinedBehaviorSanitizer enabled to take full advantage of
* <c>uriTestMemoryManagerEx</c>. Note that environment variable
* <c>UBSAN_OPTIONS</c> may need adjustment to make UndefinedBehaviorSanitizer
* fatal (which by default it is not).
*
* @param memory <b>IN</b>: Memory manager to use, should not be NULL
* @param challengeAlignment <b>IN</b>: Whether to challenge pointer alignment
* @return Error code or 0 on success
*
* @see uriEmulateCalloc
* @see uriEmulateReallocarray
* @see UriMemoryManager
* @see uriTestMemoryManager
* @since 0.9.10
*/
URI_PUBLIC int uriTestMemoryManagerEx(UriMemoryManager * memory, UriBool challengeAlignment);



#endif /* URI_BASE_H */
31 changes: 21 additions & 10 deletions ext/uri/uriparser/src/UriCommon.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,14 +208,25 @@ UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri,
*
* For example, changing "./http://foo" into "http://foo" would change semantics
* and hence the dot segment is essential to that case and cannot be removed.
*
* Other examples that would change semantics are:
* - cutting "/.//" down to "//"
* - cutting "scheme:/.//" down to "scheme://".
*/
removeSegment = URI_TRUE;
if (relative && (walker == uri->pathHead) && (walker->next != NULL)) {
const URI_CHAR * ch = walker->next->text.first;
for (; ch < walker->next->text.afterLast; ch++) {
if (*ch == _UT(':')) {
removeSegment = URI_FALSE;
break;
if ((walker == uri->pathHead) && (walker->next != NULL)) {
/* Detect case "/.//" (with or without scheme) */
if ((walker->next->text.first == walker->next->text.afterLast)
&& (URI_FUNC(HasHost)(uri) == URI_FALSE)) {
removeSegment = URI_FALSE;
/* Detect case "./withcolon:" */
} else if (relative) {
const URI_CHAR * ch = walker->next->text.first;
for (; ch < walker->next->text.afterLast; ch++) {
if (*ch == _UT(':')) {
removeSegment = URI_FALSE;
break;
}
}
}
}
Expand Down Expand Up @@ -358,7 +369,7 @@ UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri,
}
memory->free(memory, walker);
} else {
/* Re-use segment for "" path segment to represent trailing slash, update tail */
/* Reuse segment for "" path segment to represent trailing slash, update tail */
URI_TYPE(PathSegment) * const segment = walker;
if (pathOwned && (segment->text.first != segment->text.afterLast)) {
memory->free(memory, (URI_CHAR *)segment->text.first);
Expand Down Expand Up @@ -403,7 +414,7 @@ UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri,
* NEW: tail -> NULL */
uri->pathTail = NULL;
} else {
/* Re-use segment for "" path segment to represent trailing slash,
/* Reuse segment for "" path segment to represent trailing slash,
* then update head and tail */
if (pathOwned && (walker->text.first != walker->text.afterLast)) {
memory->free(memory, (URI_CHAR *)walker->text.first);
Expand Down Expand Up @@ -696,7 +707,7 @@ static UriBool URI_FUNC(PrependNewDotSegment)(URI_TYPE(Uri) * uri, UriMemoryMana
/* When dropping a scheme from a URI without a host and with a colon (":")
* in the first path segment, a consecutive reparse would rightfully
* mis-classify the first path segment as a scheme due to the colon.
* To protect against this case, we prepend an artifical "." segment
* To protect against this case, we prepend an artificial "." segment
* to the path in here; the function is called after the scheme has
* just been dropped.
*
Expand Down Expand Up @@ -751,7 +762,7 @@ UriBool URI_FUNC(FixPathNoScheme)(URI_TYPE(Uri) * uri,
/* When dropping a host from a URI without a scheme, an absolute path
* and and empty first path segment, a consecutive reparse would rightfully
* mis-classify the first path segment as a host marker due to the "//".
* To protect against this case, we prepend an artifical "." segment
* To protect against this case, we prepend an artificial "." segment
* to the path in here; the function is called after the host has
* just been dropped.
*
Expand Down
47 changes: 43 additions & 4 deletions ext/uri/uriparser/src/UriMemory.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@



#define URI_MAX(a, b) (((a) > (b)) ? (a) : (b))

/* NOTE: This intends to mimic MALLOC_ALIGNMENT of glibc */
#define URI_MALLOC_ALIGNMENT URI_MAX(2 * sizeof(size_t), sizeof(long double))

#define URI_MALLOC_PADDING (URI_MALLOC_ALIGNMENT - sizeof(size_t))



#define URI_CHECK_ALLOC_OVERFLOW(total_size, nmemb, size) \
do { \
/* check for unsigned overflow */ \
Expand Down Expand Up @@ -170,7 +179,7 @@ void * uriEmulateReallocarray(UriMemoryManager * memory,
static void * uriDecorateMalloc(UriMemoryManager * memory,
size_t size) {
UriMemoryManager * backend;
const size_t extraBytes = sizeof(size_t);
const size_t extraBytes = sizeof(size_t) + URI_MALLOC_PADDING;
void * buffer;

if (memory == NULL) {
Expand Down Expand Up @@ -225,7 +234,7 @@ static void * uriDecorateRealloc(UriMemoryManager * memory,
return NULL;
}

prevSize = *((size_t *)((char *)ptr - sizeof(size_t)));
prevSize = *((size_t *)((char *)ptr - sizeof(size_t) - URI_MALLOC_PADDING));

/* Anything to do? */
if (size <= prevSize) {
Expand Down Expand Up @@ -259,7 +268,7 @@ static void uriDecorateFree(UriMemoryManager * memory, void * ptr) {
return;
}

backend->free(backend, (char *)ptr - sizeof(size_t));
backend->free(backend, (char *)ptr - sizeof(size_t) - URI_MALLOC_PADDING);
}


Expand Down Expand Up @@ -288,7 +297,7 @@ int uriCompleteMemoryManager(UriMemoryManager * memory,



int uriTestMemoryManager(UriMemoryManager * memory) {
int uriTestMemoryManagerEx(UriMemoryManager * memory, UriBool challengeAlignment) {
const size_t mallocSize = 7;
const size_t callocNmemb = 3;
const size_t callocSize = 5;
Expand Down Expand Up @@ -456,11 +465,41 @@ int uriTestMemoryManager(UriMemoryManager * memory) {
buffer = NULL;
}

/* challenge pointer alignment */
if (challengeAlignment == URI_TRUE) {
long double * ptr = memory->malloc(memory, 4 * sizeof(long double));
if (ptr != NULL) {
ptr[0] = 0.0L;
ptr[1] = 1.1L;
ptr[2] = 2.2L;
ptr[3] = 3.3L;

{
long double * const ptrNew = memory->realloc(memory, ptr, 8 * sizeof(long double));
if (ptrNew != NULL) {
ptr = ptrNew;
ptr[4] = 4.4L;
ptr[5] = 5.5L;
ptr[6] = 6.6L;
ptr[7] = 7.7L;
}
}

memory->free(memory, ptr);
}
}

return URI_SUCCESS;
}



int uriTestMemoryManager(UriMemoryManager * memory) {
return uriTestMemoryManagerEx(memory, /*challengeAlignment=*/ URI_FALSE);
}



/*extern*/ UriMemoryManager defaultMemoryManager = {
uriDefaultMalloc,
uriDefaultCalloc,
Expand Down
Loading