Skip to content

Printing 45 VARIATION SELECTOR-16 characters after an emoji causes stack buffer overflow in encode_utf8 #8318

Description

@balaziks

Describe the bug
Printing 45 VARIATION SELECTOR-16 characters after an emoji causes stack buffer overflow in encode_utf8

To Reproduce
Steps to reproduce the behavior:

  1. Run kitty
  2. Run python3 -c 'print("\N{HEAVY EXCLAMATION MARK SYMBOL}" + 45 * "\N{VARIATION SELECTOR-16}")'
  3. Observe the crash.

Environment details

Linux framework 6.12.10-arch1-1 #1 SMP PREEMPT_DYNAMIC Sat, 18 Jan 2025 02:26:57 +0000 x86_64
S{PRETTY_NAME} 6.12.10-arch1-1 (/dev/tty)

DISTRIB_ID="Arch"
DISTRIB_RELEASE="rolling"
DISTRIB_DESCRIPTION="Arch Linux"
Running under: Wayland (sway version 1.10) missing: blur
OpenGL: '4.6 (Core Profile) Mesa 24.3.3-arch1.2' Detected version: 4.6
Frozen: False
Fonts:
  medium: NotoSansMono-Regular: /usr/share/fonts/noto/NotoSansMono-Regular.ttf:0
          Features: ()
    bold: NotoSansMono-Bold: /usr/share/fonts/noto/NotoSansMono-Bold.ttf:0
          Features: ()
  italic: NotoSansMono-Regular: /usr/share/fonts/noto/NotoSansMono-Regular.ttf:0
          Features: ()
      bi: NotoSansMono-Bold: /usr/share/fonts/noto/NotoSansMono-Bold.ttf:0
          Features: ()
Paths:
  kitty: /home/stepan/tmp/kitty/kitty/launcher/kitty
  base dir: /home/stepan/tmp/kitty
  extensions dir: /home/stepan/tmp/kitty/kitty
  system shell: /bin/bash
System color scheme: no_preference. Applied color theme type: none

Config options different from defaults:

Important environment variables seen by the kitty process:
	PATH                                /home/stepan/tmp/kitty/kitty/launcher:/home/stepan/.pyenv/shims:/home/stepan/.local/bin:/home/stepan/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/home/stepan/.local/bin:/home/stepan/.local/bin
	LANG                                en_US.UTF-8
	EDITOR                              nvim
	SHELL                               /bin/bash
	DISPLAY                             :0
	WAYLAND_DISPLAY                     wayland-1
	USER                                stepan
	XCURSOR_SIZE                        24
	XDG_DATA_HOME                       /home/stepan/.local/share
	XDG_CONFIG_HOME                     /home/stepan/.config
	XDG_SEAT                            seat0
	XDG_SESSION_TYPE                    wayland
	XDG_DOWNLOAD_DIR                    /home/stepan/tmp
	XDG_CACHE_HOME                      /home/stepan/.cache
	XDG_SESSION_CLASS                   user
	XDG_DESKTOP_DIR                     /home/stepan/tmp
	XDG_VTNR                            1
	XDG_SESSION_ID                      1
	XDG_STATE_HOME                      /home/stepan/.local/state
	XDG_RUNTIME_DIR                     /run/user/1000

Additional context

"\N{NAME OF THE CHARACTER}" is the pythonic way of getting a Unicode character by its name.

VARIATION SELECTOR-16 is used to hint the renderer to render the emoji in the emoji variant (meaning "❗️" rather than "❗︎").

Using it multiple times in a row is surely against the Unicode spec but kitty should not crash.

Running with sanitizers I get:

=================================================================
==125315==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ae4804bd560 at pc 0x7ae47c4a0d7c bp 0x7ffe0671e050 sp 0x7ffe0671e040
WRITE of size 1 at 0x7ae4804bd560 thread T0
    #0 0x7ae47c4a0d7b in encode_utf8 kitty/charsets.c:242
    #1 0x7ae47c573e9e in chars_as_utf8 kitty/fonts.c:671
    #2 0x7ae47c5741f1 in fallback_font kitty/fonts.c:685
    #3 0x7ae47c574d5d in font_for_cell kitty/fonts.c:756
    #4 0x7ae47c57a7b1 in render_line kitty/fonts.c:1839
    #5 0x7ae47c70e67c in screen_update_cell_data kitty/screen.c:3274
    #6 0x7ae47c72c37c in cell_prepare_to_render kitty/shaders.c:510
    #7 0x7ae47c7390d1 in send_cell_data_to_gpu kitty/shaders.c:1064
    #8 0x7ae47c4aaed1 in prepare_to_render_os_window kitty/child-monitor.c:784
    #9 0x7ae47c4bd170 in render_os_window kitty/child-monitor.c:881
    #10 0x7ae47c4bdaf2 in render kitty/child-monitor.c:908
    #11 0x7ae47c4bdca4 in process_global_state kitty/child-monitor.c:1291
    #12 0x7ae47c4bddb7 in do_state_check kitty/child-monitor.c:1272
    #13 0x7ae474f60b26 in dispatchTimers glfw/backend_utils.c:208
    #14 0x7ae474f613b6 in pollForEvents glfw/backend_utils.c:309
    #15 0x7ae474f11fe0 in handleEvents glfw/wl_window.c:1248
    #16 0x7ae474f209f3 in _glfwPlatformWaitEvents glfw/wl_window.c:1790
    #17 0x7ae474f07d82 in _glfwPlatformRunMainLoop glfw/main_loop.h:30
    #18 0x7ae474ee30f9 in glfwRunMainLoop glfw/init.c:360
    #19 0x7ae47c5e6a55 in run_main_loop kitty/glfw.c:2195
    #20 0x7ae47c4a1551 in main_loop kitty/child-monitor.c:1316
    #21 0x7ae48326f9e6 in method_vectorcall_NOARGS Objects/descrobject.c:454
    #22 0x7ae483167bf9 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:92
    #23 0x7ae4832f8b9c in PyObject_Vectorcall Objects/call.c:325
    #24 0x7ae4832f8b9c in _PyEval_EvalFrameDefault Python/bytecodes.c:2706
    #25 0x7ae483270756 in _PyObject_FastCallDictTstate Objects/call.c:133
    #26 0x7ae483288e39 in _PyObject_Call_Prepend Objects/call.c:508
    #27 0x7ae483288e39 in slot_tp_call Objects/typeobject.c:8770
    #28 0x7ae483270641 in _PyObject_MakeTpCall Objects/call.c:240
    #29 0x7ae4832f8b9c in PyObject_Vectorcall Objects/call.c:325
    #30 0x7ae4832f8b9c in _PyEval_EvalFrameDefault Python/bytecodes.c:2706
    #31 0x7ae48330820b in _PyEval_EvalFrame Include/internal/pycore_ceval.h:89
    #32 0x7ae48330820b in _PyEval_Vector Python/ceval.c:1683
    #33 0x7ae48330820b in PyEval_EvalCode Python/ceval.c:578
    #34 0x7ae48339e252 in builtin_exec_impl.isra.27 Python/bltinmodule.c:1096
    #35 0x7ae48339e252 in builtin_exec Python/clinic/bltinmodule.c.h:586
    #36 0x7ae48323d3c3 in cfunction_vectorcall_FASTCALL_KEYWORDS Objects/methodobject.c:438
    #37 0x7ae483167bf9 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:92
    #38 0x7ae4832f8b9c in PyObject_Vectorcall Objects/call.c:325
    #39 0x7ae4832f8b9c in _PyEval_EvalFrameDefault Python/bytecodes.c:2706
    #40 0x7ae48327bcc7 in _PyVectorcall_Call Objects/call.c:271
    #41 0x7ae48327bcc7 in _PyObject_Call Objects/call.c:354
    #42 0x7ae48339494d in pymain_run_module Modules/main.c:300
    #43 0x7ae4831ff91f in pymain_run_python Modules/main.c:626
    #44 0x7ae4831ff91f in Py_RunMain Modules/main.c:709
    #45 0x5888c9555049 in run_embedded kitty/launcher/main.c:217
    #46 0x5888c9557fe8 in main kitty/launcher/main.c:467
    #47 0x7ae482634e07  (/usr/lib/libc.so.6+0x25e07) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #48 0x7ae482634ecb in __libc_start_main (/usr/lib/libc.so.6+0x25ecb) (BuildId: 98b3d8e0b8c534c769cb871c438b4f8f3a8e4bf3)
    #49 0x5888c95516d4 in _start (/home/stepan/tmp/kitty/kitty/launcher/kitty+0x136d4) (BuildId: 2cf0ae18c01e6b24941e1965bc1714fb7fe9317c)

Address 0x7ae4804bd560 is located in stack of thread T0 at offset 352 in frame
    #0 0x7ae47c573fe5 in fallback_font kitty/fonts.c:678

  This frame has 4 object(s):
    [32, 64) 'fi' (line 686)
    [96, 128) 'itr' (line 678)
    [160, 192) 'itr'
    [224, 352) 'cell_text' (line 684) <== Memory access at offset 352 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow kitty/charsets.c:242 in encode_utf8
Shadow bytes around the buggy address:
  0x7ae4804bd280: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7ae4804bd300: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5
  0x7ae4804bd380: f5 f5 f5 f5 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ae4804bd400: f1 f1 f1 f1 00 00 00 00 f2 f2 f2 f2 00 00 00 00
  0x7ae4804bd480: f2 f2 f2 f2 00 00 00 00 f2 f2 f2 f2 00 00 00 00
=>0x7ae4804bd500: 00 00 00 00 00 00 00 00 00 00 00 00[f3]f3 f3 f3
  0x7ae4804bd580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ae4804bd600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ae4804bd680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ae4804bd700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7ae4804bd780: 00 00 00 00 00 00 00 00 00 00 00 00 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
==125315==ABORTING

This has been originally found by @nicki-krizek and minimized by me.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions