On 1/8/25 7:00 PM, jor...@apache.org wrote:
> Author: jorton
> Date: Wed Jan  8 18:00:29 2025
> New Revision: 1922994
> 
> URL: http://svn.apache.org/viewvc?rev=1922994&view=rev
> Log:
> * modules/generators/mod_autoindex.c (dsortf): Ensure the function
>   is transitive to avoid undefined behaviour, per:
>   https://www.qualys.com/2024/01/30/qsort.txt
> 
> Submitted by: Kuan-Wei Chiu <visitorckw gmail.com>
> Github: closes #500
> 
> Modified:
>     httpd/httpd/trunk/modules/generators/mod_autoindex.c
> 
> Modified: httpd/httpd/trunk/modules/generators/mod_autoindex.c
> URL: 
> http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/generators/mod_autoindex.c?rev=1922994&r1=1922993&r2=1922994&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/generators/mod_autoindex.c (original)
> +++ httpd/httpd/trunk/modules/generators/mod_autoindex.c Wed Jan  8 18:00:29 
> 2025
> @@ -1923,8 +1923,13 @@ static int dsortf(struct ent **e1, struc
>  
>      /*
>       * First, see if either of the entries is for the parent directory.
> -     * If so, that *always* sorts lower than anything else.
> +     * If so, that *always* sorts lower than anything else. The
> +     * function must be transitive else behaviour is undefined, although
> +     * in no real case should both entries start with a '/'.
>       */
> +    if ((*e1)->name[0] == '/' && (*e2)->name[0] == '/') {
> +        return 0;
> +    }
>      if ((*e1)->name[0] == '/') {
>          return -1;
>      }
> 
> 

I am fine with the change and sorry for getting into a theoretical discussion 
here, but I think the function before the patch was
transitive (at least regarding to the '/' topic. I have not checked other 
cases):

Let's assume x = '/', y = '/', z = '/'

dsortf(x, y) == -1
dsortf(y, z) == -1
dsortf(x, z) == -1

Transitive

Let's assume x = !'/', y = '/', z = '/'

dsortf(x, y) == 1
dsortf(y, z) == -1
dsortf(x, z) == 1

But as the first two do not deliver the same results it does not matter.

Let's assume x = '/', y = !'/', z = '/'

dsortf(x, y) == -1
dsortf(y, z) == 1
dsortf(x, z) == -1

But as the first two do not deliver the same results it does not matter.

Let's assume x = '/', y = '/', z = !'/'

dsortf(x, y) == -1
dsortf(y, z) == -1
dsortf(x, z) == -1

Transitive

Let's assume x = !'/', y = !'/', z = '/'

dsortf(x, y) ==  whatever
dsortf(y, z) == 1
dsortf(x, z) == 1

If whatever == 1 it is transitive if not it does not matter as the first two do 
not deliver the same results


Let's assume x = '/', y = !'/', z = !'/'

dsortf(x, y) == -1
dsortf(y, z) == whatever
dsortf(x, z) == -1

If whatever == -1 it is transitive if not it does not matter as the first two 
do not deliver the same results

Or did I miss a case related to '/'?


The unpatched version is not reflexive though:

dsortf('/', '/') should be 0 but it is -1. After the patch it is 0.

The unpatched version is also not antisymmetric:

as dsortf('/', '/') != -dsortf('/', '/')

After the patch: dsortf('/', '/') == -dsortf('/', '/')



Regards

RĂ¼diger

Reply via email to