# [PATCH 0/2] Replace atoi() with strtol_i2()

24 messages from 2024-01-22 to 2024-02-04. Participants: Mohit Marathe via GitGitGadget, Junio C Hamano, Mohit Marathe.
Thread: https://gitlist.dev/t/60779

## Mohit Marathe via GitGitGadget, 2024-01-22 08:51

Subject: [PATCH 0/2] Replace atoi() with strtol_i2()
Message-ID: <pull.1646.git.1705913519.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/pull.1646.git.1705913519.gitgitgadget%40gmail.com

```
Hello,

This patch series replaces atoi() with an updated version of strtol_i()
called strtol_i2 (Credits: Junio C Hamano). The reasoning behind this is to
improve error handling by not allowing non-numerical characters in the hunk
header (which might happen in case of a corrupt patch, although rarely).

There is still a change to be made, as Junio says: "A corrupt patch may be
getting a nonsense patch-ID with the current code and hopefully is not
matching other patches that are not corrupt, but with such a change, a
corrupt patch may not be getting any patch-ID and a loop that computes
patch-ID for many files and try to match them up might need to be rewritten
to take the new failure case into account." I'm not sure where this change
needs to me made (maybe get_one_patchid()?). It would be great if anyone
could point me to the correct place.

Thanks, Mohit Marathe

Mohit Marathe (2):
  git-compat-util: add strtol_i2
  patch-id: replace `atoi()` with `strtol_i2()`

 builtin/patch-id.c | 14 +++++++-------
 git-compat-util.h  | 23 +++++++++++++++++++++++
 2 files changed, 30 insertions(+), 7 deletions(-)


base-commit: e02ecfcc534e2021aae29077a958dd11c3897e4c
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1646%2Fmohit-marathe%2Fupdate-strtol_i-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1646/mohit-marathe/update-strtol_i-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/1646
-- 
gitgitgadget

```

## Mohit Marathe via GitGitGadget, 2024-01-22 08:51

Subject: [PATCH 1/2] git-compat-util: add strtol_i2
Message-ID: <4e2b03cdd4f57d91f1993c5e89e28f9115033161.1705913519.git.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/4e2b03cdd4f57d91f1993c5e89e28f9115033161.1705913519.git.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.git.1705913519.gitgitgadget@gmail.com>

```
From: Mohit Marathe <mohitmarathe23@gmail.com>

This function is an updated version of strtol_i function. It will
give more control to handle parsing of the characters after the
integer and better error handling while parsing numbers.

Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
---
 git-compat-util.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/git-compat-util.h b/git-compat-util.h
index 7c2a6538e5a..0a014c837d8 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -1309,6 +1309,29 @@ static inline int strtol_i(char const *s, int base, int *result)
 	return 0;
 }
 
+#define strtol_i(s,b,r) strtol_i2((s), (b), (r), NULL)
+static inline int strtol_i2(char const *s, int base, int *result, char **endp)
+{
+	long ul;
+	char *dummy = NULL;
+
+	if (!endp)
+		endp = &dummy;
+	errno = 0;
+	ul = strtol(s, endp, base);
+	if (errno ||
+	    /*
+	     * if we are told to parse to the end of the string by
+	     * passing NULL to endp, it is an error to have any
+	     * remaining character after the digits.
+	     */
+	   (dummy && *dummy) ||
+	    *endp == s || (int) ul != ul)
+		return -1;
+	*result = ul;
+	return 0;
+}
+
 void git_stable_qsort(void *base, size_t nmemb, size_t size,
 		      int(*compar)(const void *, const void *));
 #ifdef INTERNAL_QSORT
-- 
gitgitgadget


```

## Mohit Marathe via GitGitGadget, 2024-01-22 08:51

Subject: [PATCH 2/2] patch-id: replace `atoi()` with `strtol_i2()`
Message-ID: <1ece724b1ca7f71542bfef42795fce798563ecde.1705913519.git.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/1ece724b1ca7f71542bfef42795fce798563ecde.1705913519.git.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.git.1705913519.gitgitgadget@gmail.com>

```
From: Mohit Marathe <mohitmarathe23@gmail.com>

The change is made to improve the error-handling capabilities
during the conversion of string representations to integers.
The `strtol_i2(` function offers a more robust mechanism for
converting strings to integers by providing enhanced error
detection. Unlike `atoi(`, `strtol_i2(` allows the code to
differentiate between a valid conversion and an invalid one,
offering better resilience against potential issues such as
reading hunk header of a corrupted patch.

Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
---
 builtin/patch-id.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 3894d2b9706..6bfb263de5e 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -1,3 +1,4 @@
+#include "git-compat-util.h"
 #include "builtin.h"
 #include "config.h"
 #include "diff.h"
@@ -29,33 +30,32 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
 {
 	static const char digits[] = "0123456789";
 	const char *q, *r;
+	char *endp;
 	int n;
 
 	q = p + 4;
 	n = strspn(q, digits);
 	if (q[n] == ',') {
 		q += n + 1;
-		*p_before = atoi(q);
+		if (strtol_i2(q, 10, p_before, &endp) != 0)
+			return 0;
 		n = strspn(q, digits);
 	} else {
 		*p_before = 1;
 	}
 
-	if (n == 0 || q[n] != ' ' || q[n+1] != '+')
+	if (q[n] != ' ' || q[n+1] != '+')
 		return 0;
 
 	r = q + n + 2;
 	n = strspn(r, digits);
 	if (r[n] == ',') {
 		r += n + 1;
-		*p_after = atoi(r);
-		n = strspn(r, digits);
+		if (strtol_i2(r, 10, p_after, &endp) != 0)
+			return 0;
 	} else {
 		*p_after = 1;
 	}
-	if (n == 0)
-		return 0;
-
 	return 1;
 }
 
-- 
gitgitgadget

```

## Junio C Hamano, 2024-01-22 19:32

Subject: Re: [PATCH 2/2] patch-id: replace `atoi()` with `strtol_i2()`
Message-ID: <xmqq8r4htb8r.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqq8r4htb8r.fsf%40gitster.g
In-Reply-To: <1ece724b1ca7f71542bfef42795fce798563ecde.1705913519.git.gitgitgadget@gmail.com>

```
"Mohit Marathe via GitGitGadget" <gitgitgadget@gmail.com> writes:

>  	static const char digits[] = "0123456789";
>  	const char *q, *r;
> +	char *endp;
>  	int n;
>  
>  	q = p + 4;
>  	n = strspn(q, digits);
>  	if (q[n] == ',') {
>  		q += n + 1;
> -		*p_before = atoi(q);
> +		if (strtol_i2(q, 10, p_before, &endp) != 0)
> +			return 0;
>  		n = strspn(q, digits);
>  	} else {
>  		*p_before = 1;
>  	}

Looking at this code again, because we upfront run strspn() to make
sure q[] begins with a run of digits *and* followed by a comma
(which is not a digit), I think it is safe to use atoi() and assume
it would slurp all the digits.  So the lack of another check the use
of new helper allows us to do, namely

		if (endp != q + n)
			return 0;

is probably OK, but that is one of the two reasons why you would
favor the use of new helper over atoi(), so the upside of this
change is not all that great as I originally hoped for X-<.

Not your fault, of course.  We would still catch when the digit
string that starts q[] is too large to fit in an int, which is an
upside.

> -	if (n == 0 || q[n] != ' ' || q[n+1] != '+')
> +	if (q[n] != ' ' || q[n+1] != '+')
>  		return 0;

When we saw q[] that begins with ',' upon entry to this function, we
used to say *p_before = 1 and then saw n==0 and realized it is not a
good input and returned 0 from the function.

Now we instead peek q[0] and the check says q[0] is not SP so we
will return 0 the same way so there is no behaviour change from the
upper hunk?  The conversion may be correct, but it wasn't explained
in the proposed commit log message.

How are the change to stop caring about n==0 here ...

>  	r = q + n + 2;
>  	n = strspn(r, digits);
>  	if (r[n] == ',') {
>  		r += n + 1;
> -		*p_after = atoi(r);
> -		n = strspn(r, digits);
> +		if (strtol_i2(r, 10, p_after, &endp) != 0)
> +			return 0;
>  	} else {
>  		*p_after = 1;
>  	}
> -	if (n == 0)
> -		return 0;

... and this change here, linked to the switch from atoi() to
strtul_i2()[*]?

It looks like an unrelated behaviour change that is left
unexplained.

>  	return 1;
>  }

Thanks for working on this one.


[Footnote]

 * by the way, what a horrible name for a public function.  Yuck.

```

## Mohit Marathe, 2024-01-24 04:22

Subject: Re: [PATCH 2/2] patch-id: replace `atoi()` with `strtol_i2()`
Message-ID: <cwwH6NrWMc0fRUiirzvQmY-FoUS12K1SLSkBAbbu_QgAR7aDlvby6hgI_puXwtRSwX86zw6FQjUs1yHcPm8LcxuWhDnfG-4f0XRMjtTIVwU=@proton.me>
URL: https://gitlist.dev/e/cwwH6NrWMc0fRUiirzvQmY-FoUS12K1SLSkBAbbu_QgAR7aDlvby6hgI_puXwtRSwX86zw6FQjUs1yHcPm8LcxuWhDnfG-4f0XRMjtTIVwU%3D%40proton.me
In-Reply-To: <xmqq8r4htb8r.fsf@gitster.g>

```

On Tuesday, January 23rd, 2024 at 1:02 AM, Junio C Hamano <gitster@pobox.com> wrote:

> "Mohit Marathe via GitGitGadget" gitgitgadget@gmail.com writes:
> 
> > static const char digits[] = "0123456789";
> > const char *q, *r;
> > + char *endp;
> > int n;
> > 
> > q = p + 4;
> > n = strspn(q, digits);
> > if (q[n] == ',') {
> > q += n + 1;
> > - *p_before = atoi(q);
> > + if (strtol_i2(q, 10, p_before, &endp) != 0)
> > + return 0;
> > n = strspn(q, digits);
> > } else {
> > *p_before = 1;
> > }
> 
> 
> Looking at this code again, because we upfront run strspn() to make
> sure q[] begins with a run of digits and followed by a comma
> (which is not a digit), I think it is safe to use atoi() and assume
> it would slurp all the digits. So the lack of another check the use
> of new helper allows us to do, namely
> 
> if (endp != q + n)
> return 0;
> 
> is probably OK, but that is one of the two reasons why you would
> favor the use of new helper over atoi(), so the upside of this
> change is not all that great as I originally hoped for X-<.
> 
> Not your fault, of course. We would still catch when the digit
> string that starts q[] is too large to fit in an int, which is an
> upside.
> 
> > - if (n == 0 || q[n] != ' ' || q[n+1] != '+')
> > + if (q[n] != ' ' || q[n+1] != '+')
> > return 0;
> 
> 
> When we saw q[] that begins with ',' upon entry to this function, we
> used to say *p_before = 1 and then saw n==0 and realized it is not a
> good input and returned 0 from the function.

Uh oh, I just looked at the `if` block and concluded that it was just 
to check if it has numbers after the ',', which`strtol_i2()` already 
does. But I totally missed this one. 

> Now we instead peek q[0] and the check says q[0] is not SP so we
> will return 0 the same way so there is no behaviour change from the
> upper hunk? The conversion may be correct, but it wasn't explained
> in the proposed commit log message.
> 
> How are the change to stop caring about n==0 here ...
> 
> > r = q + n + 2;
> > n = strspn(r, digits);
> > if (r[n] == ',') {
> > r += n + 1;
> > - *p_after = atoi(r);
> > - n = strspn(r, digits);
> > + if (strtol_i2(r, 10, p_after, &endp) != 0)
> > + return 0;
> > } else {
> > *p_after = 1;
> > }
> > - if (n == 0)
> > - return 0;
> 
> 
> ... and this change here, linked to the switch from atoi() to
> strtul_i2()[*]?
> 
> It looks like an unrelated behaviour change that is left
> unexplained.
> 
> > return 1;
> > }
> 
> 
> Thanks for working on this one.
> 
> 
> [Footnote]
> 
> * by the way, what a horrible name for a public function. Yuck.

Yeah, I thought so too /:D How does `strtol_i_updated` sounds?

Thanks for you feedback! I will send v2 with the corrections soon.

```

## Mohit Marathe via GitGitGadget, 2024-01-24 06:32

Subject: [PATCH v2 1/2] git-compat-util: add strtol_i_updated()
Message-ID: <60ea85a701a05831b0adf1e3f9a7a97fd31ef43f.1706077977.git.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/60ea85a701a05831b0adf1e3f9a7a97fd31ef43f.1706077977.git.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v2.git.1706077977.gitgitgadget@gmail.com>

```
From: Mohit Marathe <mohitmarathe23@gmail.com>

This function is an updated version of strtol_i() function. It will
give more control to handle parsing of the characters after the
integer and better error handling while parsing numbers.

Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
---
 git-compat-util.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/git-compat-util.h b/git-compat-util.h
index 7c2a6538e5a..b38d7c7f8f1 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -1309,6 +1309,29 @@ static inline int strtol_i(char const *s, int base, int *result)
 	return 0;
 }
 
+#define strtol_i(s,b,r) strtol_i_updated((s), (b), (r), NULL)
+static inline int strtol_i_updated(char const *s, int base, int *result, char **endp)
+{
+	long ul;
+	char *dummy = NULL;
+
+	if (!endp)
+		endp = &dummy;
+	errno = 0;
+	ul = strtol(s, endp, base);
+	if (errno ||
+	    /*
+	     * if we are told to parse to the end of the string by
+	     * passing NULL to endp, it is an error to have any
+	     * remaining character after the digits.
+	     */
+	   (dummy && *dummy) ||
+	    *endp == s || (int) ul != ul)
+		return -1;
+	*result = ul;
+	return 0;
+}
+
 void git_stable_qsort(void *base, size_t nmemb, size_t size,
 		      int(*compar)(const void *, const void *));
 #ifdef INTERNAL_QSORT
-- 
gitgitgadget


```

## Mohit Marathe via GitGitGadget, 2024-01-24 06:32

Subject: [PATCH v2 0/2] Replace atoi() with strtol_i_updated()
Message-ID: <pull.1646.v2.git.1706077977.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/pull.1646.v2.git.1706077977.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.git.1705913519.gitgitgadget@gmail.com>

```
Hello,

This patch series replaces atoi() with an updated version of strtol_i()
called strtol_i_updated (Credits: Junio C Hamano). The reasoning behind this
is to improve error handling by not allowing non-numerical characters in the
hunk header (which might happen in case of a corrupt patch, although
rarely).

There is still a change to be made, as Junio says: "A corrupt patch may be
getting a nonsense patch-ID with the current code and hopefully is not
matching other patches that are not corrupt, but with such a change, a
corrupt patch may not be getting any patch-ID and a loop that computes
patch-ID for many files and try to match them up might need to be rewritten
to take the new failure case into account." I'm not sure where this change
needs to me made (maybe get_one_patchid()?). It would be great if anyone
could point me to the correct place.

Thanks, Mohit Marathe

Mohit Marathe (2):
  git-compat-util: add strtol_i_updated()
  patch-id: replace `atoi()` with `strtol_i_updated()`

 builtin/patch-id.c |  8 ++++++--
 git-compat-util.h  | 23 +++++++++++++++++++++++
 2 files changed, 29 insertions(+), 2 deletions(-)


base-commit: e02ecfcc534e2021aae29077a958dd11c3897e4c
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1646%2Fmohit-marathe%2Fupdate-strtol_i-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1646/mohit-marathe/update-strtol_i-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/1646

Range-diff vs v1:

 1:  4e2b03cdd4f ! 1:  60ea85a701a git-compat-util: add strtol_i2
     @@ Metadata
      Author: Mohit Marathe <mohitmarathe23@gmail.com>
      
       ## Commit message ##
     -    git-compat-util: add strtol_i2
     +    git-compat-util: add strtol_i_updated()
      
     -    This function is an updated version of strtol_i function. It will
     +    This function is an updated version of strtol_i() function. It will
          give more control to handle parsing of the characters after the
          integer and better error handling while parsing numbers.
      
     @@ git-compat-util.h: static inline int strtol_i(char const *s, int base, int *resu
       	return 0;
       }
       
     -+#define strtol_i(s,b,r) strtol_i2((s), (b), (r), NULL)
     -+static inline int strtol_i2(char const *s, int base, int *result, char **endp)
     ++#define strtol_i(s,b,r) strtol_i_updated((s), (b), (r), NULL)
     ++static inline int strtol_i_updated(char const *s, int base, int *result, char **endp)
      +{
      +	long ul;
      +	char *dummy = NULL;
 2:  1ece724b1ca ! 2:  f3a03d68211 patch-id: replace `atoi()` with `strtol_i2()`
     @@ Metadata
      Author: Mohit Marathe <mohitmarathe23@gmail.com>
      
       ## Commit message ##
     -    patch-id: replace `atoi()` with `strtol_i2()`
     +    patch-id: replace `atoi()` with `strtol_i_updated()`
      
          The change is made to improve the error-handling capabilities
          during the conversion of string representations to integers.
     -    The `strtol_i2(` function offers a more robust mechanism for
     +    The `strtol_i_updated(` function offers a more robust mechanism for
          converting strings to integers by providing enhanced error
     -    detection. Unlike `atoi(`, `strtol_i2(` allows the code to
     +    detection. Unlike `atoi(`, `strtol_i_updated(` allows the code to
          differentiate between a valid conversion and an invalid one,
          offering better resilience against potential issues such as
          reading hunk header of a corrupted patch.
     @@ builtin/patch-id.c: static int scan_hunk_header(const char *p, int *p_before, in
       	if (q[n] == ',') {
       		q += n + 1;
      -		*p_before = atoi(q);
     -+		if (strtol_i2(q, 10, p_before, &endp) != 0)
     ++		if (strtol_i_updated(q, 10, p_before, &endp) != 0)
      +			return 0;
       		n = strspn(q, digits);
       	} else {
       		*p_before = 1;
     - 	}
     - 
     --	if (n == 0 || q[n] != ' ' || q[n+1] != '+')
     -+	if (q[n] != ' ' || q[n+1] != '+')
     - 		return 0;
     - 
     - 	r = q + n + 2;
     +@@ builtin/patch-id.c: static int scan_hunk_header(const char *p, int *p_before, int *p_after)
       	n = strspn(r, digits);
       	if (r[n] == ',') {
       		r += n + 1;
      -		*p_after = atoi(r);
     --		n = strspn(r, digits);
     -+		if (strtol_i2(r, 10, p_after, &endp) != 0)
     ++		if (strtol_i_updated(r, 10, p_after, &endp) != 0)
      +			return 0;
     + 		n = strspn(r, digits);
       	} else {
       		*p_after = 1;
     - 	}
     --	if (n == 0)
     --		return 0;
     --
     - 	return 1;
     - }
     - 

-- 
gitgitgadget

```

## Mohit Marathe via GitGitGadget, 2024-01-24 06:32

Subject: [PATCH v2 2/2] patch-id: replace `atoi()` with `strtol_i_updated()`
Message-ID: <f3a03d68211bc79b41562762c8ca63889b9218b2.1706077977.git.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/f3a03d68211bc79b41562762c8ca63889b9218b2.1706077977.git.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v2.git.1706077977.gitgitgadget@gmail.com>

```
From: Mohit Marathe <mohitmarathe23@gmail.com>

The change is made to improve the error-handling capabilities
during the conversion of string representations to integers.
The `strtol_i_updated(` function offers a more robust mechanism for
converting strings to integers by providing enhanced error
detection. Unlike `atoi(`, `strtol_i_updated(` allows the code to
differentiate between a valid conversion and an invalid one,
offering better resilience against potential issues such as
reading hunk header of a corrupted patch.

Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
---
 builtin/patch-id.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 3894d2b9706..e513b6aed3f 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -1,3 +1,4 @@
+#include "git-compat-util.h"
 #include "builtin.h"
 #include "config.h"
 #include "diff.h"
@@ -29,13 +30,15 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
 {
 	static const char digits[] = "0123456789";
 	const char *q, *r;
+	char *endp;
 	int n;
 
 	q = p + 4;
 	n = strspn(q, digits);
 	if (q[n] == ',') {
 		q += n + 1;
-		*p_before = atoi(q);
+		if (strtol_i_updated(q, 10, p_before, &endp) != 0)
+			return 0;
 		n = strspn(q, digits);
 	} else {
 		*p_before = 1;
@@ -48,7 +51,8 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
 	n = strspn(r, digits);
 	if (r[n] == ',') {
 		r += n + 1;
-		*p_after = atoi(r);
+		if (strtol_i_updated(r, 10, p_after, &endp) != 0)
+			return 0;
 		n = strspn(r, digits);
 	} else {
 		*p_after = 1;
-- 
gitgitgadget

```

## Mohit Marathe via GitGitGadget, 2024-01-24 06:48

Subject: [PATCH v3 0/2] Replace atoi() with strtol_i_updated()
Message-ID: <pull.1646.v3.git.1706078885.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/pull.1646.v3.git.1706078885.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v2.git.1706077977.gitgitgadget@gmail.com>

```
Hello,

This patch series replaces atoi() with an updated version of strtol_i()
called strtol_i_updated (Credits: Junio C Hamano). The reasoning behind this
is to improve error handling by not allowing non-numerical characters in the
hunk header (which might happen in case of a corrupt patch, although
rarely).

There is still a change to be made, as Junio says: "A corrupt patch may be
getting a nonsense patch-ID with the current code and hopefully is not
matching other patches that are not corrupt, but with such a change, a
corrupt patch may not be getting any patch-ID and a loop that computes
patch-ID for many files and try to match them up might need to be rewritten
to take the new failure case into account." I'm not sure where this change
needs to me made (maybe get_one_patchid()?). It would be great if anyone
could point me to the correct place.

Thanks, Mohit Marathe

Mohit Marathe (2):
  git-compat-util: add strtol_i_updated()
  patch-id: replace `atoi()` with `strtol_i_updated()`

 builtin/patch-id.c | 12 ++++++++++--
 git-compat-util.h  | 23 +++++++++++++++++++++++
 2 files changed, 33 insertions(+), 2 deletions(-)


base-commit: e02ecfcc534e2021aae29077a958dd11c3897e4c
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1646%2Fmohit-marathe%2Fupdate-strtol_i-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1646/mohit-marathe/update-strtol_i-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/1646

Range-diff vs v2:

 1:  60ea85a701a = 1:  60ea85a701a git-compat-util: add strtol_i_updated()
 2:  f3a03d68211 ! 2:  0e117198d01 patch-id: replace `atoi()` with `strtol_i_updated()`
     @@ builtin/patch-id.c: static int scan_hunk_header(const char *p, int *p_before, in
      +		if (strtol_i_updated(q, 10, p_before, &endp) != 0)
      +			return 0;
       		n = strspn(q, digits);
     ++		if (endp != q + n)
     ++			return 0;
       	} else {
       		*p_before = 1;
     + 	}
      @@ builtin/patch-id.c: static int scan_hunk_header(const char *p, int *p_before, int *p_after)
       	n = strspn(r, digits);
       	if (r[n] == ',') {
     @@ builtin/patch-id.c: static int scan_hunk_header(const char *p, int *p_before, in
      +		if (strtol_i_updated(r, 10, p_after, &endp) != 0)
      +			return 0;
       		n = strspn(r, digits);
     ++		if (endp != q + n)
     ++			return 0;
       	} else {
       		*p_after = 1;
     + 	}

-- 
gitgitgadget

```

## Mohit Marathe via GitGitGadget, 2024-01-24 06:48

Subject: [PATCH v3 1/2] git-compat-util: add strtol_i_updated()
Message-ID: <60ea85a701a05831b0adf1e3f9a7a97fd31ef43f.1706078885.git.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/60ea85a701a05831b0adf1e3f9a7a97fd31ef43f.1706078885.git.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v3.git.1706078885.gitgitgadget@gmail.com>

```
From: Mohit Marathe <mohitmarathe23@gmail.com>

This function is an updated version of strtol_i() function. It will
give more control to handle parsing of the characters after the
integer and better error handling while parsing numbers.

Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
---
 git-compat-util.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/git-compat-util.h b/git-compat-util.h
index 7c2a6538e5a..b38d7c7f8f1 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -1309,6 +1309,29 @@ static inline int strtol_i(char const *s, int base, int *result)
 	return 0;
 }
 
+#define strtol_i(s,b,r) strtol_i_updated((s), (b), (r), NULL)
+static inline int strtol_i_updated(char const *s, int base, int *result, char **endp)
+{
+	long ul;
+	char *dummy = NULL;
+
+	if (!endp)
+		endp = &dummy;
+	errno = 0;
+	ul = strtol(s, endp, base);
+	if (errno ||
+	    /*
+	     * if we are told to parse to the end of the string by
+	     * passing NULL to endp, it is an error to have any
+	     * remaining character after the digits.
+	     */
+	   (dummy && *dummy) ||
+	    *endp == s || (int) ul != ul)
+		return -1;
+	*result = ul;
+	return 0;
+}
+
 void git_stable_qsort(void *base, size_t nmemb, size_t size,
 		      int(*compar)(const void *, const void *));
 #ifdef INTERNAL_QSORT
-- 
gitgitgadget


```

## Mohit Marathe via GitGitGadget, 2024-01-24 06:48

Subject: [PATCH v3 2/2] patch-id: replace `atoi()` with `strtol_i_updated()`
Message-ID: <0e117198d0144fa4ee6ccf01ec31a099eaf8121c.1706078885.git.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/0e117198d0144fa4ee6ccf01ec31a099eaf8121c.1706078885.git.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v3.git.1706078885.gitgitgadget@gmail.com>

```
From: Mohit Marathe <mohitmarathe23@gmail.com>

The change is made to improve the error-handling capabilities
during the conversion of string representations to integers.
The `strtol_i_updated(` function offers a more robust mechanism for
converting strings to integers by providing enhanced error
detection. Unlike `atoi(`, `strtol_i_updated(` allows the code to
differentiate between a valid conversion and an invalid one,
offering better resilience against potential issues such as
reading hunk header of a corrupted patch.

Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
---
 builtin/patch-id.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 3894d2b9706..2c00d45cb2c 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -1,3 +1,4 @@
+#include "git-compat-util.h"
 #include "builtin.h"
 #include "config.h"
 #include "diff.h"
@@ -29,14 +30,18 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
 {
 	static const char digits[] = "0123456789";
 	const char *q, *r;
+	char *endp;
 	int n;
 
 	q = p + 4;
 	n = strspn(q, digits);
 	if (q[n] == ',') {
 		q += n + 1;
-		*p_before = atoi(q);
+		if (strtol_i_updated(q, 10, p_before, &endp) != 0)
+			return 0;
 		n = strspn(q, digits);
+		if (endp != q + n)
+			return 0;
 	} else {
 		*p_before = 1;
 	}
@@ -48,8 +53,11 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
 	n = strspn(r, digits);
 	if (r[n] == ',') {
 		r += n + 1;
-		*p_after = atoi(r);
+		if (strtol_i_updated(r, 10, p_after, &endp) != 0)
+			return 0;
 		n = strspn(r, digits);
+		if (endp != q + n)
+			return 0;
 	} else {
 		*p_after = 1;
 	}
-- 
gitgitgadget

```

## Mohit Marathe via GitGitGadget, 2024-01-24 06:55

Subject: [PATCH v4 0/2] Replace atoi() with strtol_i_updated()
Message-ID: <pull.1646.v4.git.1706079304.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/pull.1646.v4.git.1706079304.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v3.git.1706078885.gitgitgadget@gmail.com>

```
Hello,

This patch series replaces atoi() with an updated version of strtol_i()
called strtol_i_updated (Credits: Junio C Hamano). The reasoning behind this
is to improve error handling by not allowing non-numerical characters in the
hunk header (which might happen in case of a corrupt patch, although
rarely).

There is still a change to be made, as Junio says: "A corrupt patch may be
getting a nonsense patch-ID with the current code and hopefully is not
matching other patches that are not corrupt, but with such a change, a
corrupt patch may not be getting any patch-ID and a loop that computes
patch-ID for many files and try to match them up might need to be rewritten
to take the new failure case into account." I'm not sure where this change
needs to me made (maybe get_one_patchid()?). It would be great if anyone
could point me to the correct place.

Thanks, Mohit Marathe

Mohit Marathe (2):
  git-compat-util: add strtol_i_updated()
  patch-id: replace `atoi()` with `strtol_i_updated()`

 builtin/patch-id.c | 12 ++++++++++--
 git-compat-util.h  | 23 +++++++++++++++++++++++
 2 files changed, 33 insertions(+), 2 deletions(-)


base-commit: e02ecfcc534e2021aae29077a958dd11c3897e4c
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1646%2Fmohit-marathe%2Fupdate-strtol_i-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1646/mohit-marathe/update-strtol_i-v4
Pull-Request: https://github.com/gitgitgadget/git/pull/1646

Range-diff vs v3:

 1:  60ea85a701a = 1:  60ea85a701a git-compat-util: add strtol_i_updated()
 2:  0e117198d01 ! 2:  17f2dda4907 patch-id: replace `atoi()` with `strtol_i_updated()`
     @@ builtin/patch-id.c: static int scan_hunk_header(const char *p, int *p_before, in
      +		if (strtol_i_updated(r, 10, p_after, &endp) != 0)
      +			return 0;
       		n = strspn(r, digits);
     -+		if (endp != q + n)
     ++		if (endp != r + n)
      +			return 0;
       	} else {
       		*p_after = 1;

-- 
gitgitgadget

```

## Mohit Marathe via GitGitGadget, 2024-01-24 06:55

Subject: [PATCH v4 1/2] git-compat-util: add strtol_i_updated()
Message-ID: <60ea85a701a05831b0adf1e3f9a7a97fd31ef43f.1706079304.git.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/60ea85a701a05831b0adf1e3f9a7a97fd31ef43f.1706079304.git.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v4.git.1706079304.gitgitgadget@gmail.com>

```
From: Mohit Marathe <mohitmarathe23@gmail.com>

This function is an updated version of strtol_i() function. It will
give more control to handle parsing of the characters after the
integer and better error handling while parsing numbers.

Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
---
 git-compat-util.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/git-compat-util.h b/git-compat-util.h
index 7c2a6538e5a..b38d7c7f8f1 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -1309,6 +1309,29 @@ static inline int strtol_i(char const *s, int base, int *result)
 	return 0;
 }
 
+#define strtol_i(s,b,r) strtol_i_updated((s), (b), (r), NULL)
+static inline int strtol_i_updated(char const *s, int base, int *result, char **endp)
+{
+	long ul;
+	char *dummy = NULL;
+
+	if (!endp)
+		endp = &dummy;
+	errno = 0;
+	ul = strtol(s, endp, base);
+	if (errno ||
+	    /*
+	     * if we are told to parse to the end of the string by
+	     * passing NULL to endp, it is an error to have any
+	     * remaining character after the digits.
+	     */
+	   (dummy && *dummy) ||
+	    *endp == s || (int) ul != ul)
+		return -1;
+	*result = ul;
+	return 0;
+}
+
 void git_stable_qsort(void *base, size_t nmemb, size_t size,
 		      int(*compar)(const void *, const void *));
 #ifdef INTERNAL_QSORT
-- 
gitgitgadget


```

## Mohit Marathe via GitGitGadget, 2024-01-24 06:55

Subject: [PATCH v4 2/2] patch-id: replace `atoi()` with `strtol_i_updated()`
Message-ID: <17f2dda4907ec03b0783160c53c4896fd76cb053.1706079304.git.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/17f2dda4907ec03b0783160c53c4896fd76cb053.1706079304.git.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v4.git.1706079304.gitgitgadget@gmail.com>

```
From: Mohit Marathe <mohitmarathe23@gmail.com>

The change is made to improve the error-handling capabilities
during the conversion of string representations to integers.
The `strtol_i_updated(` function offers a more robust mechanism for
converting strings to integers by providing enhanced error
detection. Unlike `atoi(`, `strtol_i_updated(` allows the code to
differentiate between a valid conversion and an invalid one,
offering better resilience against potential issues such as
reading hunk header of a corrupted patch.

Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
---
 builtin/patch-id.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 3894d2b9706..88db178c905 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -1,3 +1,4 @@
+#include "git-compat-util.h"
 #include "builtin.h"
 #include "config.h"
 #include "diff.h"
@@ -29,14 +30,18 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
 {
 	static const char digits[] = "0123456789";
 	const char *q, *r;
+	char *endp;
 	int n;
 
 	q = p + 4;
 	n = strspn(q, digits);
 	if (q[n] == ',') {
 		q += n + 1;
-		*p_before = atoi(q);
+		if (strtol_i_updated(q, 10, p_before, &endp) != 0)
+			return 0;
 		n = strspn(q, digits);
+		if (endp != q + n)
+			return 0;
 	} else {
 		*p_before = 1;
 	}
@@ -48,8 +53,11 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
 	n = strspn(r, digits);
 	if (r[n] == ',') {
 		r += n + 1;
-		*p_after = atoi(r);
+		if (strtol_i_updated(r, 10, p_after, &endp) != 0)
+			return 0;
 		n = strspn(r, digits);
+		if (endp != r + n)
+			return 0;
 	} else {
 		*p_after = 1;
 	}
-- 
gitgitgadget

```

## Junio C Hamano, 2024-01-24 20:20

Subject: Re: [PATCH v4 1/2] git-compat-util: add strtol_i_updated()
Message-ID: <xmqqede6cwkg.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqqede6cwkg.fsf%40gitster.g
In-Reply-To: <60ea85a701a05831b0adf1e3f9a7a97fd31ef43f.1706079304.git.gitgitgadget@gmail.com>

```
"Mohit Marathe via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Mohit Marathe <mohitmarathe23@gmail.com>
>
> This function is an updated version of strtol_i() function. It will
> give more control to handle parsing of the characters after the
> integer and better error handling while parsing numbers.

i2 was horrible but this is worse.  What would you call an even
newer variant when you need to add one?  strtol_i_updated_twice?

To readers who are reading the code in 6 months, it is totally
uninteresting that strtol_i() is an older function and the new thing
was invented later as its update.  What they want to learn is how
these two are different, what additional things this new one lets
them do compared to the old one, namely: we can optionally learn
where the run of the digits has ended.

Perhaps call it "strtoi_with_tail" or something, unless others
suggest even better names?

Thanks.

```

## Junio C Hamano, 2024-01-24 21:02

Subject: Re: [PATCH v4 2/2] patch-id: replace `atoi()` with `strtol_i_updated()`
Message-ID: <xmqqttn2bg2o.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqqttn2bg2o.fsf%40gitster.g
In-Reply-To: <17f2dda4907ec03b0783160c53c4896fd76cb053.1706079304.git.gitgitgadget@gmail.com>

```
"Mohit Marathe via GitGitGadget" <gitgitgadget@gmail.com> writes:

>  	q = p + 4;
>  	n = strspn(q, digits);
>  	if (q[n] == ',') {
>  		q += n + 1;

So, we saw "@@ -" and skipped over these four bytes, skipped the
digits from there, and found a comma.  

For "@@ -29,14 +30,18 @@", for example, our q is now "14 +30,18 @@"
as we have skipped over that comma after 29.

> -		*p_before = atoi(q);
> +		if (strtol_i_updated(q, 10, p_before, &endp) != 0)
> +			return 0;

We parse out 14 and store it to *p_before.  endp points at " +30..."
now.

>  		n = strspn(q, digits);
> +		if (endp != q + n)
> +			return 0;

Is this necessary?  By asking strtol_i_updated() where the number ended,
we already know endp without skipping the digits in q with strspn().
Shouldn't these three lines become more like

		n = endp - q;

instead?  

After all, we are not trying to find a bug in strtol_i_updated(),
which would be the only reason how this "return 0" would trigger.

>  	} else {
>  		*p_before = 1;
>  	}
> @@ -48,8 +53,11 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
>  	n = strspn(r, digits);
>  	if (r[n] == ',') {
>  		r += n + 1;
> -		*p_after = atoi(r);
> +		if (strtol_i_updated(r, 10, p_after, &endp) != 0)
> +			return 0;
>  		n = strspn(r, digits);
> +		if (endp != r + n)
> +			return 0;

Likewise.

>  	} else {
>  		*p_after = 1;
>  	}


```

## Mohit Marathe, 2024-01-28 04:35

Subject: Re: [PATCH v4 2/2] patch-id: replace `atoi()` with `strtol_i_updated()`
Message-ID: <0d_yXUwMsJQsIySLnVJ5SlpFi2YdTgnvVN5cLCbwt_V4pVOUipzFEPlFY1xLicHfe4SGsWwF5D1q1idGBVyRXXr6tME-GR6hQG7usi5mypw=@proton.me>
URL: https://gitlist.dev/e/0d_yXUwMsJQsIySLnVJ5SlpFi2YdTgnvVN5cLCbwt_V4pVOUipzFEPlFY1xLicHfe4SGsWwF5D1q1idGBVyRXXr6tME-GR6hQG7usi5mypw%3D%40proton.me
In-Reply-To: <xmqqttn2bg2o.fsf@gitster.g>

```

On Thursday, January 25th, 2024 at 2:32 AM, Junio C Hamano <gitster@pobox.com> wrote:

> "Mohit Marathe via GitGitGadget" gitgitgadget@gmail.com writes:
> 
> > q = p + 4;
> > n = strspn(q, digits);
> > if (q[n] == ',') {
> > q += n + 1;
> 
> 
> So, we saw "@@ -" and skipped over these four bytes, skipped the
> digits from there, and found a comma.
> 
> For "@@ -29,14 +30,18 @@", for example, our q is now "14 +30,18 @@"
> as we have skipped over that comma after 29.
> 
> > - *p_before = atoi(q);
> > + if (strtol_i_updated(q, 10, p_before, &endp) != 0)
> > + return 0;
> 
> 
> We parse out 14 and store it to *p_before. endp points at " +30..."
> now.
> 
> > n = strspn(q, digits);
> > + if (endp != q + n)
> > + return 0;
> 
> 
> Is this necessary? By asking strtol_i_updated() where the number ended,
> we already know endp without skipping the digits in q with strspn().
> Shouldn't these three lines become more like
> 
> n = endp - q;
> 
> instead?
> 
> After all, we are not trying to find a bug in strtol_i_updated(),
> which would be the only reason how this "return 0" would trigger.
> 

I was confused about how an invalid hunk header of a corrupted would
look like. This was just an attempt of making a sanity check. But after
taking another look, I agree that its unnecessary.

> > } else {
> > *p_before = 1;
> > }
> > @@ -48,8 +53,11 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
> > n = strspn(r, digits);
> > if (r[n] == ',') {
> > r += n + 1;
> > - *p_after = atoi(r);
> > + if (strtol_i_updated(r, 10, p_after, &endp) != 0)
> > + return 0;
> > n = strspn(r, digits);
> > + if (endp != r + n)
> > + return 0;
> 
> 
> Likewise.
> 
> > } else {
> > *p_after = 1;
> > }

```

## Mohit Marathe via GitGitGadget, 2024-01-28 04:42

Subject: [PATCH v5 0/2] Replace atoi() with strtoi_with_tail()
Message-ID: <pull.1646.v5.git.1706416952.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/pull.1646.v5.git.1706416952.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v4.git.1706079304.gitgitgadget@gmail.com>

```
Hello,

This patch series replaces atoi() with an updated version of strtol_i()
called strtoi_with_tail (Credits: Junio C Hamano). The reasoning behind this
is to improve error handling by not allowing non-numerical characters in the
hunk header (which might happen in case of a corrupt patch, although
rarely).

There is still a change to be made, as Junio says: "A corrupt patch may be
getting a nonsense patch-ID with the current code and hopefully is not
matching other patches that are not corrupt, but with such a change, a
corrupt patch may not be getting any patch-ID and a loop that computes
patch-ID for many files and try to match them up might need to be rewritten
to take the new failure case into account." I'm not sure where this change
needs to me made (maybe get_one_patchid()?). It would be great if anyone
could point me to the correct place.

Thanks, Mohit Marathe

Mohit Marathe (2):
  git-compat-util: add strtoi_with_tail()
  patch-id: replace `atoi()` with `strtoi_with_tail`

 builtin/patch-id.c | 12 ++++++++----
 git-compat-util.h  | 23 +++++++++++++++++++++++
 2 files changed, 31 insertions(+), 4 deletions(-)


base-commit: b50a608ba20348cb3dfc16a696816d51780e3f0f
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1646%2Fmohit-marathe%2Fupdate-strtol_i-v5
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1646/mohit-marathe/update-strtol_i-v5
Pull-Request: https://github.com/gitgitgadget/git/pull/1646

Range-diff vs v4:

 1:  60ea85a701a ! 1:  f09b0838f04 git-compat-util: add strtol_i_updated()
     @@ Metadata
      Author: Mohit Marathe <mohitmarathe23@gmail.com>
      
       ## Commit message ##
     -    git-compat-util: add strtol_i_updated()
     +    git-compat-util: add strtoi_with_tail()
      
          This function is an updated version of strtol_i() function. It will
          give more control to handle parsing of the characters after the
     -    integer and better error handling while parsing numbers.
     +    numbers and better error handling while parsing numbers.
      
          Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
      
     @@ git-compat-util.h: static inline int strtol_i(char const *s, int base, int *resu
       	return 0;
       }
       
     -+#define strtol_i(s,b,r) strtol_i_updated((s), (b), (r), NULL)
     -+static inline int strtol_i_updated(char const *s, int base, int *result, char **endp)
     ++#define strtol_i(s,b,r) strtoi_with_tail((s), (b), (r), NULL)
     ++static inline int strtoi_with_tail(char const *s, int base, int *result, char **endp)
      +{
      +	long ul;
      +	char *dummy = NULL;
 2:  17f2dda4907 ! 2:  ee8f4ae991d patch-id: replace `atoi()` with `strtol_i_updated()`
     @@ Metadata
      Author: Mohit Marathe <mohitmarathe23@gmail.com>
      
       ## Commit message ##
     -    patch-id: replace `atoi()` with `strtol_i_updated()`
     +    patch-id: replace `atoi()` with `strtoi_with_tail`
      
          The change is made to improve the error-handling capabilities
     -    during the conversion of string representations to integers.
     -    The `strtol_i_updated(` function offers a more robust mechanism for
     +    during the conversion of string to integers. The
     +    `strtoi_with_tail` function offers a more robust mechanism for
          converting strings to integers by providing enhanced error
     -    detection. Unlike `atoi(`, `strtol_i_updated(` allows the code to
     +    detection. Unlike `atoi`, `strtoi_with_tail` allows the code to
          differentiate between a valid conversion and an invalid one,
          offering better resilience against potential issues such as
          reading hunk header of a corrupted patch.
     @@ builtin/patch-id.c: static int scan_hunk_header(const char *p, int *p_before, in
       	if (q[n] == ',') {
       		q += n + 1;
      -		*p_before = atoi(q);
     -+		if (strtol_i_updated(q, 10, p_before, &endp) != 0)
     -+			return 0;
     - 		n = strspn(q, digits);
     -+		if (endp != q + n)
     +-		n = strspn(q, digits);
     ++		if (strtoi_with_tail(q, 10, p_before, &endp) != 0)
      +			return 0;
     ++		n = endp - q;
       	} else {
       		*p_before = 1;
       	}
     @@ builtin/patch-id.c: static int scan_hunk_header(const char *p, int *p_before, in
       	if (r[n] == ',') {
       		r += n + 1;
      -		*p_after = atoi(r);
     -+		if (strtol_i_updated(r, 10, p_after, &endp) != 0)
     -+			return 0;
     - 		n = strspn(r, digits);
     -+		if (endp != r + n)
     +-		n = strspn(r, digits);
     ++		if (strtoi_with_tail(r, 10, p_after, &endp) != 0)
      +			return 0;
     ++		n = endp - r;
       	} else {
       		*p_after = 1;
       	}

-- 
gitgitgadget

```

## Mohit Marathe via GitGitGadget, 2024-01-28 04:42

Subject: [PATCH v5 1/2] git-compat-util: add strtoi_with_tail()
Message-ID: <f09b0838f049de3e4b8cc6adc6cd4492bac7e967.1706416952.git.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/f09b0838f049de3e4b8cc6adc6cd4492bac7e967.1706416952.git.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v5.git.1706416952.gitgitgadget@gmail.com>

```
From: Mohit Marathe <mohitmarathe23@gmail.com>

This function is an updated version of strtol_i() function. It will
give more control to handle parsing of the characters after the
numbers and better error handling while parsing numbers.

Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
---
 git-compat-util.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/git-compat-util.h b/git-compat-util.h
index 7c2a6538e5a..c576b1b104f 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -1309,6 +1309,29 @@ static inline int strtol_i(char const *s, int base, int *result)
 	return 0;
 }
 
+#define strtol_i(s,b,r) strtoi_with_tail((s), (b), (r), NULL)
+static inline int strtoi_with_tail(char const *s, int base, int *result, char **endp)
+{
+	long ul;
+	char *dummy = NULL;
+
+	if (!endp)
+		endp = &dummy;
+	errno = 0;
+	ul = strtol(s, endp, base);
+	if (errno ||
+	    /*
+	     * if we are told to parse to the end of the string by
+	     * passing NULL to endp, it is an error to have any
+	     * remaining character after the digits.
+	     */
+	   (dummy && *dummy) ||
+	    *endp == s || (int) ul != ul)
+		return -1;
+	*result = ul;
+	return 0;
+}
+
 void git_stable_qsort(void *base, size_t nmemb, size_t size,
 		      int(*compar)(const void *, const void *));
 #ifdef INTERNAL_QSORT
-- 
gitgitgadget


```

## Mohit Marathe via GitGitGadget, 2024-01-28 04:42

Subject: [PATCH v5 2/2] patch-id: replace `atoi()` with `strtoi_with_tail`
Message-ID: <ee8f4ae991d71d399a9c07086f56a38f7531b6cf.1706416952.git.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/ee8f4ae991d71d399a9c07086f56a38f7531b6cf.1706416952.git.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v5.git.1706416952.gitgitgadget@gmail.com>

```
From: Mohit Marathe <mohitmarathe23@gmail.com>

The change is made to improve the error-handling capabilities
during the conversion of string to integers. The
`strtoi_with_tail` function offers a more robust mechanism for
converting strings to integers by providing enhanced error
detection. Unlike `atoi`, `strtoi_with_tail` allows the code to
differentiate between a valid conversion and an invalid one,
offering better resilience against potential issues such as
reading hunk header of a corrupted patch.

Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
---
 builtin/patch-id.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 3894d2b9706..4e9a301e9fb 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -1,3 +1,4 @@
+#include "git-compat-util.h"
 #include "builtin.h"
 #include "config.h"
 #include "diff.h"
@@ -29,14 +30,16 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
 {
 	static const char digits[] = "0123456789";
 	const char *q, *r;
+	char *endp;
 	int n;
 
 	q = p + 4;
 	n = strspn(q, digits);
 	if (q[n] == ',') {
 		q += n + 1;
-		*p_before = atoi(q);
-		n = strspn(q, digits);
+		if (strtoi_with_tail(q, 10, p_before, &endp) != 0)
+			return 0;
+		n = endp - q;
 	} else {
 		*p_before = 1;
 	}
@@ -48,8 +51,9 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
 	n = strspn(r, digits);
 	if (r[n] == ',') {
 		r += n + 1;
-		*p_after = atoi(r);
-		n = strspn(r, digits);
+		if (strtoi_with_tail(r, 10, p_after, &endp) != 0)
+			return 0;
+		n = endp - r;
 	} else {
 		*p_after = 1;
 	}
-- 
gitgitgadget

```

## Junio C Hamano, 2024-01-30 04:40

Subject: Re: [PATCH v5 1/2] git-compat-util: add strtoi_with_tail()
Message-ID: <xmqqle87e8nx.fsf@gitster.g>
URL: https://gitlist.dev/e/xmqqle87e8nx.fsf%40gitster.g
In-Reply-To: <f09b0838f049de3e4b8cc6adc6cd4492bac7e967.1706416952.git.gitgitgadget@gmail.com>

```
"Mohit Marathe via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Mohit Marathe <mohitmarathe23@gmail.com>
>
> This function is an updated version of strtol_i() function. It will
> give more control to handle parsing of the characters after the
> numbers and better error handling while parsing numbers.
>
> Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
> ---
>  git-compat-util.h | 23 +++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
>
> diff --git a/git-compat-util.h b/git-compat-util.h
> index 7c2a6538e5a..c576b1b104f 100644
> --- a/git-compat-util.h
> +++ b/git-compat-util.h
> @@ -1309,6 +1309,29 @@ static inline int strtol_i(char const *s, int base, int *result)
>  	return 0;
>  }

Are we leaving the original one above?  Shouldn't this step instead
remove it, as strtol_i() is now a C preprocessor macro as seen below?

> +#define strtol_i(s,b,r) strtoi_with_tail((s), (b), (r), NULL)
> +static inline int strtoi_with_tail(char const *s, int base, int *result, char **endp)
> +{
> +	long ul;
> +	char *dummy = NULL;
> +
> +	if (!endp)
> +		endp = &dummy;
> +	errno = 0;
> +	ul = strtol(s, endp, base);
> +	if (errno ||
> +	    /*
> +	     * if we are told to parse to the end of the string by
> +	     * passing NULL to endp, it is an error to have any
> +	     * remaining character after the digits.
> +	     */
> +	   (dummy && *dummy) ||
> +	    *endp == s || (int) ul != ul)
> +		return -1;
> +	*result = ul;
> +	return 0;
> +}
> +
>  void git_stable_qsort(void *base, size_t nmemb, size_t size,
>  		      int(*compar)(const void *, const void *));
>  #ifdef INTERNAL_QSORT

```

## Mohit Marathe via GitGitGadget, 2024-02-04 05:48

Subject: [PATCH v6 0/2] Replace atoi() with strtoi_with_tail()
Message-ID: <pull.1646.v6.git.1707025718.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/pull.1646.v6.git.1707025718.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v5.git.1706416952.gitgitgadget@gmail.com>

```
Hello,

This patch series replaces atoi() with an updated version of strtol_i()
called strtoi_with_tail (Credits: Junio C Hamano). The reasoning behind this
is to improve error handling by not allowing non-numerical characters in the
hunk header (which might happen in case of a corrupt patch, although
rarely).

There is still a change to be made, as Junio says: "A corrupt patch may be
getting a nonsense patch-ID with the current code and hopefully is not
matching other patches that are not corrupt, but with such a change, a
corrupt patch may not be getting any patch-ID and a loop that computes
patch-ID for many files and try to match them up might need to be rewritten
to take the new failure case into account." I'm not sure where this change
needs to me made (maybe get_one_patchid()?). It would be great if anyone
could point me to the correct place.

Thanks, Mohit Marathe

Mohit Marathe (2):
  git-compat-util: add strtoi_with_tail()
  patch-id: replace `atoi()` with `strtoi_with_tail`

 builtin/patch-id.c | 12 ++++++++----
 git-compat-util.h  | 18 ++++++++++++++----
 2 files changed, 22 insertions(+), 8 deletions(-)


base-commit: 2a540e432fe5dff3cfa9d3bf7ca56db2ad12ebb9
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1646%2Fmohit-marathe%2Fupdate-strtol_i-v6
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1646/mohit-marathe/update-strtol_i-v6
Pull-Request: https://github.com/gitgitgadget/git/pull/1646

Range-diff vs v5:

 1:  f09b0838f04 ! 1:  98e516a7be7 git-compat-util: add strtoi_with_tail()
     @@ Commit message
          Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
      
       ## git-compat-util.h ##
     -@@ git-compat-util.h: static inline int strtol_i(char const *s, int base, int *result)
     +@@ git-compat-util.h: static inline int strtoul_ui(char const *s, int base, unsigned int *result)
       	return 0;
       }
       
     +-static inline int strtol_i(char const *s, int base, int *result)
      +#define strtol_i(s,b,r) strtoi_with_tail((s), (b), (r), NULL)
      +static inline int strtoi_with_tail(char const *s, int base, int *result, char **endp)
     -+{
     -+	long ul;
     + {
     + 	long ul;
     +-	char *p;
      +	char *dummy = NULL;
     -+
     + 
      +	if (!endp)
      +		endp = &dummy;
     -+	errno = 0;
     + 	errno = 0;
     +-	ul = strtol(s, &p, base);
     +-	if (errno || *p || p == s || (int) ul != ul)
      +	ul = strtol(s, endp, base);
      +	if (errno ||
      +	    /*
     @@ git-compat-util.h: static inline int strtol_i(char const *s, int base, int *resu
      +	     */
      +	   (dummy && *dummy) ||
      +	    *endp == s || (int) ul != ul)
     -+		return -1;
     -+	*result = ul;
     -+	return 0;
     -+}
     -+
     - void git_stable_qsort(void *base, size_t nmemb, size_t size,
     - 		      int(*compar)(const void *, const void *));
     - #ifdef INTERNAL_QSORT
     + 		return -1;
     + 	*result = ul;
     + 	return 0;
 2:  ee8f4ae991d = 2:  858d6f94e79 patch-id: replace `atoi()` with `strtoi_with_tail`

-- 
gitgitgadget

```

## Mohit Marathe via GitGitGadget, 2024-02-04 05:48

Subject: [PATCH v6 1/2] git-compat-util: add strtoi_with_tail()
Message-ID: <98e516a7be777f2697073e64b28c293e7a8a0011.1707025719.git.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/98e516a7be777f2697073e64b28c293e7a8a0011.1707025719.git.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v6.git.1707025718.gitgitgadget@gmail.com>

```
From: Mohit Marathe <mohitmarathe23@gmail.com>

This function is an updated version of strtol_i() function. It will
give more control to handle parsing of the characters after the
numbers and better error handling while parsing numbers.

Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
---
 git-compat-util.h | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/git-compat-util.h b/git-compat-util.h
index 7c2a6538e5a..59256a441de 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -1296,14 +1296,24 @@ static inline int strtoul_ui(char const *s, int base, unsigned int *result)
 	return 0;
 }
 
-static inline int strtol_i(char const *s, int base, int *result)
+#define strtol_i(s,b,r) strtoi_with_tail((s), (b), (r), NULL)
+static inline int strtoi_with_tail(char const *s, int base, int *result, char **endp)
 {
 	long ul;
-	char *p;
+	char *dummy = NULL;
 
+	if (!endp)
+		endp = &dummy;
 	errno = 0;
-	ul = strtol(s, &p, base);
-	if (errno || *p || p == s || (int) ul != ul)
+	ul = strtol(s, endp, base);
+	if (errno ||
+	    /*
+	     * if we are told to parse to the end of the string by
+	     * passing NULL to endp, it is an error to have any
+	     * remaining character after the digits.
+	     */
+	   (dummy && *dummy) ||
+	    *endp == s || (int) ul != ul)
 		return -1;
 	*result = ul;
 	return 0;
-- 
gitgitgadget


```

## Mohit Marathe via GitGitGadget, 2024-02-04 05:48

Subject: [PATCH v6 2/2] patch-id: replace `atoi()` with `strtoi_with_tail`
Message-ID: <858d6f94e79ba388267cc24f43ebf68998cd56a8.1707025719.git.gitgitgadget@gmail.com>
URL: https://gitlist.dev/e/858d6f94e79ba388267cc24f43ebf68998cd56a8.1707025719.git.gitgitgadget%40gmail.com
In-Reply-To: <pull.1646.v6.git.1707025718.gitgitgadget@gmail.com>

```
From: Mohit Marathe <mohitmarathe23@gmail.com>

The change is made to improve the error-handling capabilities
during the conversion of string to integers. The
`strtoi_with_tail` function offers a more robust mechanism for
converting strings to integers by providing enhanced error
detection. Unlike `atoi`, `strtoi_with_tail` allows the code to
differentiate between a valid conversion and an invalid one,
offering better resilience against potential issues such as
reading hunk header of a corrupted patch.

Signed-off-by: Mohit Marathe <mohitmarathe@proton.me>
---
 builtin/patch-id.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/builtin/patch-id.c b/builtin/patch-id.c
index 3894d2b9706..4e9a301e9fb 100644
--- a/builtin/patch-id.c
+++ b/builtin/patch-id.c
@@ -1,3 +1,4 @@
+#include "git-compat-util.h"
 #include "builtin.h"
 #include "config.h"
 #include "diff.h"
@@ -29,14 +30,16 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
 {
 	static const char digits[] = "0123456789";
 	const char *q, *r;
+	char *endp;
 	int n;
 
 	q = p + 4;
 	n = strspn(q, digits);
 	if (q[n] == ',') {
 		q += n + 1;
-		*p_before = atoi(q);
-		n = strspn(q, digits);
+		if (strtoi_with_tail(q, 10, p_before, &endp) != 0)
+			return 0;
+		n = endp - q;
 	} else {
 		*p_before = 1;
 	}
@@ -48,8 +51,9 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
 	n = strspn(r, digits);
 	if (r[n] == ',') {
 		r += n + 1;
-		*p_after = atoi(r);
-		n = strspn(r, digits);
+		if (strtoi_with_tail(r, 10, p_after, &endp) != 0)
+			return 0;
+		n = endp - r;
 	} else {
 		*p_after = 1;
 	}
-- 
gitgitgadget

```
