Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streaming from URL ending in / causes memory corruption #11626

Closed
Tracked by #4379
low-batt opened this issue Apr 25, 2023 · 4 comments · Fixed by #11627
Closed
Tracked by #4379

Streaming from URL ending in / causes memory corruption #11626

low-batt opened this issue Apr 25, 2023 · 4 comments · Fixed by #11627
Labels

Comments

@low-batt
Copy link
Contributor

Important Information

Provide following Information:

  • mpv version: master
  • macOS Version: 13.3.1
  • Source of the mpv binary or bundle: My own debug build using mpv-build and Xcode 14.3
  • If known which version of mpv introduced the problem: unknown
  • Possible screenshot or video of visual glitches: N/A

Reproduction steps

In a debug version of mpv running under lldb on the Mac and configured to use libgmalloc.dylib stream this video:
https://www.tv2.no/video/nyhetene/satt-ut-av-oppvaskmaskin-triks/1810348/

Before the mpv window appears execution will stop with a EXC_BAD_ACCESS.

I found that URL in the closed issue #10886.
Possibly this explains the heap corruption reported in issue #11378.

I built a debug version of mpv using mpv-build by doing this before building:

printf "%s\n" -Dbuildtype=debug > mpv_options

My debug session is shown below, but you may not need to look into it. This statement is corrupting memory:

outbuf[osize - oleft - 1] = 0;

The method mp_iconv_to_utf8 has a bunch of input checking at the start of the method, but it is not checking to see if the string to convert passed in buf is empty. This code sequence in append_dir_subtitles:

mpv/player/external_files.c

Lines 188 to 189 in 4fd0a39

struct bstr f_fbname = bstr0(mp_basename(fname));
struct bstr f_fname = mp_iconv_to_utf8(log, f_fbname,

Is passing an empty string to mp_iconv_to_utf8 because mp_basename finds the / at the end of the URL and returns an empty string. At least I think this is what is happening.

I added this code to the start of mp_iconv_to_utf8:

    if (!buf.len)
      return buf;

With that change I was able to run mpv under lldb with libgmalloc.dylib and successfully stream the video.

Once I get this issue posted and can refer to an issue number I will post a pull request with that change. I am a total newbie at debugging mpv so a critical review of my analysis is needed.

lldb session:
low-batt@gag mpv-build (master %=)$ lldb ./mpv/build/mpv -- --config=no  --log-file=mpv.log --mute https://www.tv2.no/video/nyhetene/satt-ut-av-oppvaskmaskin-triks/1810348/
(lldb) target create "./mpv/build/mpv"
Current executable set to '/Users/low-batt/Documents/builds/mpv-build/mpv-build/mpv/build/mpv' (arm64).
(lldb) settings set -- target.run-args  "--config=no" "--log-file=mpv.log" "--mute" "https://www.tv2.no/video/nyhetene/satt-ut-av-oppvaskmaskin-triks/1810348/"
(lldb) env DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib
(lldb) process launch
Process 84056 launched: '/Users/low-batt/Documents/builds/mpv-build/mpv-build/mpv/build/mpv' (arm64)
GuardMalloc[mpv-84056]: Allocations will be placed on 16 byte boundaries.
GuardMalloc[mpv-84056]:  - Some buffer overruns may not be noticed.
GuardMalloc[mpv-84056]:  - Applications using vector instructions (e.g., SSE) should work.
GuardMalloc[mpv-84056]: version 064559.72.1
2023-04-24 16:43:47.014580-0400 mpv[84056:2489292] [Entitlements] MSVEntitlementUtilities - Process mpv PID[84056] - Group: (null) - Entitlement: com.apple.mediaremote.external-artwork-validation - Entitled: NO - Error: (null)
Process 84056 stopped
* thread #18, name = 'mpv/worker', stop reason = EXC_BAD_ACCESS (code=1, address=0x2dc1d8000)
    frame #0: 0x00000001000ecdec mpv`mp_iconv_to_utf8(log=0x00000002dc1affc0, buf=(start = "", len = 0), cp="UTF-8-MAC", flags=8) at charset_conv.c:232:31
   229 	
   230 	    iconv_close(icdsc);
   231 	
-> 232 	    outbuf[osize - oleft - 1] = 0;
   233 	    return (bstr){outbuf, osize - oleft - 1};
   234 	#endif
   235 	
Target 0: (mpv) stopped.
(lldb) frame variable
(mp_log *) log = 0x00000002dc1affc0
(bstr) buf = (start = "", len = 0)
(const char *) cp = 0x00000001013adc0b "UTF-8-MAC"
(int) flags = 8
(iconv_t) icdsc = 0x00000002dc1cff70
(size_t) size = 0
(size_t) osize = 0
(size_t) ileft = 0
(size_t) oleft = 18446744073709551615
(char *) outbuf = 0x00000002dc1d8000 ""
(char *) ip = 0x0000000159843ff9 ""
(char *) op = 0x00000002dc1d8000 ""
(lldb) thread backtrace
* thread #18, name = 'mpv/worker', stop reason = EXC_BAD_ACCESS (code=1, address=0x2dc1d8000)
  * frame #0: 0x00000001000ecdec mpv`mp_iconv_to_utf8(log=0x00000002dc1affc0, buf=(start = "", len = 0), cp="UTF-8-MAC", flags=8) at charset_conv.c:232:31
    frame #1: 0x0000000100134bdc mpv`append_dir_subtitles(global=0x0000000119c5bfd0, opts=0x000000011a1b3ad0, slist=0x0000000286592e40, nsub=0x0000000286592e3c, path=(start = "https://www.tv2.no/video/nyhetene/satt-ut-av-oppvaskmaskin-triks/1810348/", len = 73), fname="https://www.tv2.no/video/nyhetene/satt-ut-av-oppvaskmaskin-triks/1810348/", limit_fuzziness=0, limit_type=-1) at external_files.c:189:27
    frame #2: 0x0000000100134990 mpv`find_external_files(global=0x0000000119c5bfd0, fname="https://www.tv2.no/video/nyhetene/satt-ut-av-oppvaskmaskin-triks/1810348/", opts=0x000000011a1b3ad0) at external_files.c:370:5
    frame #3: 0x00000001001393cc mpv`autoload_external_files(mpctx=0x0000000119c2bb40, cancel=0x0000000119c3bf40) at loadfile.c:894:26
    frame #4: 0x000000010013de14 mpv`load_external_opts_thread(p=0x0000000119c06c58) at loadfile.c:1399:5
    frame #5: 0x00000001000f1924 mpv`worker_thread(arg=0x0000000119c43f60) at thread_pool.c:88:9
    frame #6: 0x0000000188fd7fa8 libsystem_pthread.dylib`_pthread_start + 148
(lldb) frame select 1
frame #1: 0x0000000100134bdc mpv`append_dir_subtitles(global=0x0000000119c5bfd0, opts=0x000000011a1b3ad0, slist=0x0000000286592e40, nsub=0x0000000286592e3c, path=(start = "https://www.tv2.no/video/nyhetene/satt-ut-av-oppvaskmaskin-triks/1810348/", len = 73), fname="https://www.tv2.no/video/nyhetene/satt-ut-av-oppvaskmaskin-triks/1810348/", limit_fuzziness=0, limit_type=-1) at external_files.c:189:27
   186 	    struct mp_log *log = mp_log_new(tmpmem, global->log, "find_files");
   187 	
   188 	    struct bstr f_fbname = bstr0(mp_basename(fname));
-> 189 	    struct bstr f_fname = mp_iconv_to_utf8(log, f_fbname,
   190 	                                           "UTF-8-MAC", MP_NO_LATIN1_FALLBACK);
   191 	    struct bstr f_fname_noext = bstrdup(tmpmem, bstr_strip_ext(f_fname));
   192 	    bstr_lower(f_fname_noext);
(lldb) frame variable
(mpv_global *) global = 0x0000000119c5bfd0
(MPOpts *) opts = 0x000000011a1b3ad0
(subfn **) slist = 0x0000000286592e40
(int *) nsub = 0x0000000286592e3c
(bstr) path = (start = "https://www.tv2.no/video/nyhetene/satt-ut-av-oppvaskmaskin-triks/1810348/", len = 73)
(const char *) fname = 0x0000000159843fb0 "https://www.tv2.no/video/nyhetene/satt-ut-av-oppvaskmaskin-triks/1810348/"
(int) limit_fuzziness = 0
(int) limit_type = -1
(void *) tmpmem = 0x00000002dc1a8000
(mp_log *) log = 0x00000002dc1affc0
(bstr) f_fbname = (start = "", len = 0)
(bstr) f_fname = (start = "", len = 12282626016)
(bstr) f_fname_noext = (start = "\U00000018", len = 10843925808)
(bstr) f_fname_trim = (start = 0x0000000000000000, len = 12282626016)
(char *) path0 = 0x00000002dc19ff90 "\U00000018"
(DIR *) d = 0x0000000286592d00
(dirent *) de = NULL
(lldb) 

Expected behavior

mpv can be run successfully using Guard Malloc.

Actual behavior

EXC_BAD_ACCESS

Log file

mpv.log

Sample files

https://www.tv2.no/video/nyhetene/satt-ut-av-oppvaskmaskin-triks/1810348/

low-batt added a commit to low-batt/mpv that referenced this issue Apr 25, 2023
If mp_iconv_to_utf8 was given an empty string to convert in the buf
parameter it would corrupt memory when writing a null into outbuf
before returning it to the caller. This happened when streaming from a
URL that ends in a slash. For such a URL the method mp_basename returns
an empty string. The method append_dir_subtitles passes the result
returned from mp_basename to mp_iconv_to_utf8 which then corrupts
memory. This was detected using Guard Malloc. The fix changes
mp_iconv_to_utf8 check up front if buf is empty and if it is return
buf as the result in compliance with the documented behavior of the
method when no conversion is needed.

Fixes mpv-player#11626
@krackers
Copy link

krackers commented Apr 25, 2023

I think this might also be related to #7834 it implicates the same line

Btw compiling via libgmalloc is a neat way to debug, I tried to use asan when I ran into this, but I couldn't get that to compile properly. Will have to remember this for the future...

@low-batt
Copy link
Contributor Author

I agree, this issue is a duplicate of issue #7834. I had not noticed that one. It was issue #11378 from @forthrin that caught my attention.

Note that I did not compile with libgmalloc. I switched to the Guard Malloc library at runtime by doing this:

(lldb) env DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib

That came from the lldb example in the man page for libgmalloc. I tried libgmalloc after not finding examples of enabling sanity checks when building using mpv-build.

Today I had time to explore that. I ran these commands to configure mpv-build:

printf "%s\n" --enable-debug > ffmpeg_options
printf "%s\n" -Dbuildtype=debug > mpv_options
printf "%s\n" -Db_sanitize=address,undefined >> mpv_options

And then rebuilt mpv. The address sanitizer reported the error:

==76208==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x0001091795a0 at pc 0x000102afa73c bp 0x00016dd5c710 sp 0x00016dd5c708
WRITE of size 1 at 0x0001091795a0 thread T14
    #0 0x102afa738 in mp_iconv_to_utf8 charset_conv.c:232

The address sanitizer also identifies where the heap block was allocated. Full output below.

Test run with address sanitizer:
low-batt@gag mpv-build (master %=)$ ./mpv/build/mpv --config=no  --log-file=mpv.log --mute https://www.tv2.no/video/nyhetene/satt-ut-av-oppvaskmaskin-triks/1810348/
=================================================================
==76208==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x0001091795a0 at pc 0x000102afa73c bp 0x00016dd5c710 sp 0x00016dd5c708
WRITE of size 1 at 0x0001091795a0 thread T14
    #0 0x102afa738 in mp_iconv_to_utf8 charset_conv.c:232
    #1 0x102d1031c in append_dir_subtitles external_files.c:189
    #2 0x102d0f344 in find_external_files external_files.c:370
    #3 0x102d32b84 in autoload_external_files loadfile.c:894
    #4 0x102d5ce08 in load_external_opts_thread loadfile.c:1399
    #5 0x102b1bed0 in worker_thread thread_pool.c:88
    #6 0x188fd7fa4 in _pthread_start+0x90 (libsystem_pthread.dylib:arm64e+0x6fa4) (BuildId: b401cfb38dfe32db92b3ba8af0f8ca6e32000000200000000100000000030d00)
    #7 0x188fd2d9c in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1d9c) (BuildId: b401cfb38dfe32db92b3ba8af0f8ca6e32000000200000000100000000030d00)

0x0001091795a0 is located 0 bytes to the right of 80-byte region [0x000109179550,0x0001091795a0)
allocated by thread T14 here:
    #0 0x106a3ee68 in wrap_malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x42e68) (BuildId: f0a7ac5c49bc3abc851181b6f92b308a32000000200000000100000000000b00)
    #1 0x1031e8d18 in ta_alloc_size ta.c:141
    #2 0x102af9f8c in mp_iconv_to_utf8 charset_conv.c:190
    #3 0x102d1031c in append_dir_subtitles external_files.c:189
    #4 0x102d0f344 in find_external_files external_files.c:370
    #5 0x102d32b84 in autoload_external_files loadfile.c:894
    #6 0x102d5ce08 in load_external_opts_thread loadfile.c:1399
    #7 0x102b1bed0 in worker_thread thread_pool.c:88
    #8 0x188fd7fa4 in _pthread_start+0x90 (libsystem_pthread.dylib:arm64e+0x6fa4) (BuildId: b401cfb38dfe32db92b3ba8af0f8ca6e32000000200000000100000000030d00)
    #9 0x188fd2d9c in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1d9c) (BuildId: b401cfb38dfe32db92b3ba8af0f8ca6e32000000200000000100000000030d00)

Thread T14 created by T7 here:
    #0 0x106a38d2c in wrap_pthread_create+0x54 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3cd2c) (BuildId: f0a7ac5c49bc3abc851181b6f92b308a32000000200000000100000000000b00)
    #1 0x102b18954 in add_thread thread_pool.c:146
    #2 0x102b19b44 in thread_pool_add thread_pool.c:198
    #3 0x102b19350 in mp_thread_pool_queue thread_pool.c:216
    #4 0x102c59c40 in run_command command.c:4940
    #5 0x102c30250 in run_client_command client.c:1137
    #6 0x102c30650 in mpv_command_node client.c:1155
    #7 0x1032890d4 in script_command_native lua.c:976
    #8 0x1032873fc in script_autofree_call lua.c:1270
    #9 0x10617fec0  (libluajit-5.1.2.1.0.dylib:arm64+0x3ec0) (BuildId: e5a098f954193a83b89e1dfdbb95832532000000200000000100000000000d00)
    #10 0x10618c9ec in lua_pcall+0x90 (libluajit-5.1.2.1.0.dylib:arm64+0x109ec) (BuildId: e5a098f954193a83b89e1dfdbb95832532000000200000000100000000000d00)
    #11 0x10617fec0  (libluajit-5.1.2.1.0.dylib:arm64+0x3ec0) (BuildId: e5a098f954193a83b89e1dfdbb95832532000000200000000100000000000d00)
    #12 0x1032865c4 in load_scripts lua.c:327
    #13 0x10617fec0  (libluajit-5.1.2.1.0.dylib:arm64+0x3ec0) (BuildId: e5a098f954193a83b89e1dfdbb95832532000000200000000100000000000d00)
    #14 0x10618c9ec in lua_pcall+0x90 (libluajit-5.1.2.1.0.dylib:arm64+0x109ec) (BuildId: e5a098f954193a83b89e1dfdbb95832532000000200000000100000000000d00)
    #15 0x10617fec0  (libluajit-5.1.2.1.0.dylib:arm64+0x3ec0) (BuildId: e5a098f954193a83b89e1dfdbb95832532000000200000000100000000000d00)
    #16 0x10618ca2c in lua_cpcall+0x18 (libluajit-5.1.2.1.0.dylib:arm64+0x10a2c) (BuildId: e5a098f954193a83b89e1dfdbb95832532000000200000000100000000000d00)
    #17 0x102dbf590 in run_script scripting.c:91
    #18 0x102dbfac4 in script_thread scripting.c:103
    #19 0x188fd7fa4 in _pthread_start+0x90 (libsystem_pthread.dylib:arm64e+0x6fa4) (BuildId: b401cfb38dfe32db92b3ba8af0f8ca6e32000000200000000100000000030d00)
    #20 0x188fd2d9c in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1d9c) (BuildId: b401cfb38dfe32db92b3ba8af0f8ca6e32000000200000000100000000030d00)

Thread T7 created by T3 here:
    #0 0x106a38d2c in wrap_pthread_create+0x54 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3cd2c) (BuildId: f0a7ac5c49bc3abc851181b6f92b308a32000000200000000100000000000b00)
    #1 0x102db9090 in mp_load_script scripting.c:195
    #2 0x102dba2c4 in load_builtin_script scripting.c:252
    #3 0x102db96e0 in mp_load_builtin_scripts scripting.c:263
    #4 0x102c9822c in mp_option_change_callback command.c:6869
    #5 0x102d65c08 in mp_initialize main.c:380
    #6 0x102d67fa0 in mpv_main main.c:436
    #7 0x1031f4ae4 in playback_thread macosx_application.m:280
    #8 0x188fd7fa4 in _pthread_start+0x90 (libsystem_pthread.dylib:arm64e+0x6fa4) (BuildId: b401cfb38dfe32db92b3ba8af0f8ca6e32000000200000000100000000030d00)
    #9 0x188fd2d9c in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1d9c) (BuildId: b401cfb38dfe32db92b3ba8af0f8ca6e32000000200000000100000000030d00)

Thread T3 created by T0 here:
    #0 0x106a38d2c in wrap_pthread_create+0x54 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3cd2c) (BuildId: f0a7ac5c49bc3abc851181b6f92b308a32000000200000000100000000000b00)
    #1 0x1031f3f40 in cocoa_main macosx_application.m:366
    #2 0x10320cadc in main main-fn-cocoa.c:9
    #3 0x188c7ff24  (<unknown module>)

SUMMARY: AddressSanitizer: heap-buffer-overflow charset_conv.c:232 in mp_iconv_to_utf8
Shadow bytes around the buggy address:
  0x00702124f260: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x00702124f270: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x00702124f280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x00702124f290: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x00702124f2a0: fa fa fa fa fa fa fa fa fa fa 00 00 00 00 00 00
=>0x00702124f2b0: 00 00 00 00[fa]fa fa fa 00 00 00 00 00 00 00 00
  0x00702124f2c0: 00 00 fa fa fa fa 00 00 00 00 00 00 00 00 00 00
  0x00702124f2d0: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fa fa
  0x00702124f2e0: fa fa fd fd fd fd fd fd fd fd fd fd fa fa fa fa
  0x00702124f2f0: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fd fd
  0x00702124f300: fd fd fd fd fd fd fd fd fa fa fa fa 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==76208==ABORTING
Abort trap: 6
low-batt@gag mpv-build (master %=)$ 

@forthrin
Copy link

forthrin commented Apr 26, 2023

Wow! Well spotted. If this is indeed the true culprit, its ten year anniversary is nigh. It's stuff like this that explains the popularity of Rust. (Side note: I like the idea, but not the syntax.) I'll add the pull request pointer test before the culprit line with a printf to stderr and see if that concurs with the exception, though I assume the exception doesn't necessarily trigger every time because of the unpredictable order of memory allocations. Or are you able to trigger it every time?

commit f735a03346e8ec743bc89d5bdbaafd62dc0f084d
Author: wm4 <wm4@nowhere>
Date:   Sun Jun 23 22:15:04 2013 +0200

    sub: add subtitle charset conversion
    

Update: The log statements are triggered for the video, but exceptions happen randomly, so I can't confirm correlation yet. I'll leave them in to check with other content and post updates. But in practice one of the devs will probably confirm if the PR resolves this. Better yet, someone should track down this wm4 and have him correct his own mistake.

diff --git a/misc/charset_conv.c b/misc/charset_conv.c
index 51e55c6..761bc03 100644
--- a/misc/charset_conv.c
+++ b/misc/charset_conv.c
@@ -163,0 +164,8 @@ bstr mp_iconv_to_utf8(struct mp_log *log, bstr buf, const char *cp, int flags)
+    // if (!buf.len) {
+    //   mp_err(log, "returning buf because buf.len is null\n");
+    //   return buf;
+    // }
+
+    if (!buf.len)
+      mp_err(log, "buf.len is null at start of mp_iconv_to_utf8\n");
+
@@ -231,0 +240,2 @@ bstr mp_iconv_to_utf8(struct mp_log *log, bstr buf, const char *cp, int flags)
+    if (!buf.len)
+      mp_err(log, "buf.len is null before outbuf[osize - oleft - 1] = 0;\n");

@low-batt
Copy link
Contributor Author

The fix proposed in PR #11627 is under active review.

I just streamed the example URL 3 times in a row using the released version of mpv. Played fine. As usual with heap corruption it depends upon what memory gets stepped on as to how and if the memory overwrite will manifest itself. The pattern of heap usage for applications that respond to asynchronous events and use multiple threads will vary from run to run. This makes memory corruption a critical problem that must be resolved.

The good news is that the developer tools shown above are usually effective in identifying the offending code. In the case at hand the problem was detected in every test run I did.

I took note of issue #11378 when it was first posted. I was busy at the time, so I only performed some limited testing which did not reproduce the problem. Since I had nothing to contribute I did not comment. A few days ago I was scanning open mpv issues looking to see if any new serious defects posted. I happened to check #11378 again and noticed the "keeps happening quite frequently" post. If something can be reproduced it can be tracked down. Thank you for being persistent and making sure this problem was noticed.

Dudemanguy pushed a commit that referenced this issue Apr 29, 2023
If mp_iconv_to_utf8 was given an empty string to convert in the buf
parameter it would corrupt memory when writing a null into outbuf
before returning it to the caller. This happened when streaming from a
URL that ends in a slash. For such a URL the method mp_basename returns
an empty string. The method append_dir_subtitles passes the result
returned from mp_basename to mp_iconv_to_utf8 which then corrupts
memory. This was detected using Guard Malloc. The fix changes
mp_iconv_to_utf8 check up front if buf is empty and if it is return
buf as the result in compliance with the documented behavior of the
method when no conversion is needed.

Fixes #11626
dyphire pushed a commit to dyphire/mpv that referenced this issue Jul 8, 2023
If mp_iconv_to_utf8 was given an empty string to convert in the buf
parameter it would corrupt memory when writing a null into outbuf
before returning it to the caller. This happened when streaming from a
URL that ends in a slash. For such a URL the method mp_basename returns
an empty string. The method append_dir_subtitles passes the result
returned from mp_basename to mp_iconv_to_utf8 which then corrupts
memory. This was detected using Guard Malloc. The fix changes
mp_iconv_to_utf8 check up front if buf is empty and if it is return
buf as the result in compliance with the documented behavior of the
method when no conversion is needed.

Fixes mpv-player#11626
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants