Repository: RustPython/RustPython (language: rust)

Issue:
bytes.decode doesn't honor error mode
On Windows:
```
❯ python
Python 3.13.1 (tags/v3.13.1:0671451, Dec  3 2024, 19:06:28) [MSC v.1942 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> b'test_6868_tmp\xed\xb4\x80'.decode("utf-8", "surrogatepass")
'test_6868_tmp\udd00'
>>> exit()
❯ ./target/release/rustpython
Welcome to the magnificent Rust Python 0.4.0 interpreter 😱 🖖
RustPython 3.13.0
Type "help", "copyright", "credits" or "license" for more information.
>>>>> b'test_6868_tmp\xed\xb4\x80'.decode("utf-8", "surrogatepass")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "encodings_utf_8", line 16, in decode
UnicodeDecodeError: ('utf-8', b'test_6868_tmp\xed\xb4\x80', 13, 14, 'invalid continuation byte')
>>>>> exit()
```

The rustpython demo on the web also fails (although that is really out of date).


Discussion / hints:
Seems like an inconsistency between how python and rust unicode implementations handle the bytes.
Ah it seems like rustpython does not honor decode modes:
```
❯ python                                                                                                                    
Python 3.13.1 (tags/v3.13.1:0671451, Dec  3 2024, 19:06:28) [MSC v.1942 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> b'test_6868_tmp\xed\xb4\x80'.decode("utf-8", "strict")
Traceback (most recent call last):
  File "<python-input-0>", line 1, in <module>
    b'test_6868_tmp\xed\xb4\x80'.decode("utf-8", "strict")
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xed in position 13: invalid continuation byte
>>> b'test_6868_tmp\xed\xb4\x80'.decode("utf-8", "surrogatepass")
'test_6868_tmp\udd00'
>>> 
```
While rustpython complains about a invalid continuation byte no matter what.

Fix patch:
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 3d1d32d12d..1eeecbd2a7 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -17,7 +17,6 @@ concurrency:
 env:
   CARGO_ARGS: --no-default-features --features stdlib,zlib,importlib,encodings,sqlite,ssl
   # Skip additional tests on Windows. They are checked on Linux and MacOS.
-  # test_argparse: UnicodeDecodeError
   # test_glob: many failing tests
   # test_io: many failing tests
   # test_os: many failing tests
@@ -26,7 +25,6 @@ env:
   # test_unicode: AttributeError: module '_winapi' has no attribute 'GetACP'
   # test_venv: couple of failing tests
   WINDOWS_SKIPS: >-
-    test_argparse
     test_glob
     test_io
     test_os
diff --git a/vm/src/codecs.rs b/vm/src/codecs.rs
index 898198f3d3..767bd873b6 100644
--- a/vm/src/codecs.rs
+++ b/vm/src/codecs.rs
@@ -619,11 +619,16 @@ fn surrogatepass_errors(err: PyObjectRef, vm: &VirtualMachine) -> PyResult<(PyOb
             // Not supported, fail with original exception
             return Err(err.downcast().unwrap());
         }
+
+        debug_assert!(range.start <= 0.max(s.len() - 1));
+        debug_assert!(range.end >= 1.min(s.len()));
+        debug_assert!(range.end <= s.len());
+
         let mut c: u32 = 0;
         // Try decoding a single surrogate character. If there are more,
         // let the codec call us again.
         let p = &s.as_bytes()[range.start..];
-        if p.len().saturating_sub(range.start) >= byte_length {
+        if p.len().overflowing_sub(range.start).0 >= byte_length {
             match standard_encoding {
                 StandardEncoding::Utf8 => {
                     if (p[0] as u32 & 0xf0) == 0xe0


Test patch: