Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package dmenu for openSUSE:Factory checked in at 2026-04-09 16:09:41 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/dmenu (Old) and /work/SRC/openSUSE:Factory/.dmenu.new.21863 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "dmenu" Thu Apr 9 16:09:41 2026 rev:21 rq:1345443 version:5.4 Changes: -------- --- /work/SRC/openSUSE:Factory/dmenu/dmenu.changes 2024-04-04 22:27:42.070497513 +0200 +++ /work/SRC/openSUSE:Factory/.dmenu.new.21863/dmenu.changes 2026-04-09 16:22:47.441689401 +0200 @@ -1,0 +2,9 @@ +Wed Feb 11 08:27:21 UTC 2026 - Dirk Müller <[email protected]> + +- update to 5.4: + * Avoid integer underflow in drw_text() + * render invalid utf8 sequences as U+FFFD + * overhaul utf8decode + * use XUngrabKeyboard instead of XUngrabKey + +------------------------------------------------------------------- Old: ---- dmenu-5.3.tar.gz New: ---- dmenu-5.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ dmenu.spec ++++++ --- /var/tmp/diff_new_pack.wwfPkM/_old 2026-04-09 16:22:47.965710903 +0200 +++ /var/tmp/diff_new_pack.wwfPkM/_new 2026-04-09 16:22:47.969711067 +0200 @@ -1,7 +1,7 @@ # # spec file for package dmenu # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: dmenu -Version: 5.3 +Version: 5.4 Release: 0 Summary: A generic and efficient menu for X License: MIT ++++++ dmenu-5.3.tar.gz -> dmenu-5.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dmenu-5.3/config.mk new/dmenu-5.4/config.mk --- old/dmenu-5.3/config.mk 2024-03-19 12:25:09.000000000 +0100 +++ new/dmenu-5.4/config.mk 2025-08-09 15:00:49.940271203 +0200 @@ -1,5 +1,5 @@ # dmenu version -VERSION = 5.3 +VERSION = 5.4 # paths PREFIX = /usr/local diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dmenu-5.3/dmenu.c new/dmenu-5.4/dmenu.c --- old/dmenu-5.3/dmenu.c 2024-03-19 12:25:09.000000000 +0100 +++ new/dmenu-5.4/dmenu.c 2025-08-09 15:00:49.950267502 +0200 @@ -100,7 +100,7 @@ { size_t i; - XUngrabKey(dpy, AnyKey, AnyModifier, root); + XUngrabKeyboard(dpy, CurrentTime); for (i = 0; i < SchemeLast; i++) free(scheme[i]); for (i = 0; items && items[i].text; ++i) @@ -689,7 +689,6 @@ CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); XSetClassHint(dpy, win, &ch); - /* input methods */ if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL) die("XOpenIM failed: could not open input device"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dmenu-5.3/drw.c new/dmenu-5.4/drw.c --- old/dmenu-5.3/drw.c 2024-03-19 12:25:09.000000000 +0100 +++ new/dmenu-5.4/drw.c 2025-08-09 15:00:49.950267502 +0200 @@ -9,54 +9,40 @@ #include "util.h" #define UTF_INVALID 0xFFFD -#define UTF_SIZ 4 -static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; -static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; -static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; -static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; - -static long -utf8decodebyte(const char c, size_t *i) -{ - for (*i = 0; *i < (UTF_SIZ + 1); ++(*i)) - if (((unsigned char)c & utfmask[*i]) == utfbyte[*i]) - return (unsigned char)c & ~utfmask[*i]; - return 0; -} - -static size_t -utf8validate(long *u, size_t i) +static int +utf8decode(const char *s_in, long *u, int *err) { - if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) - *u = UTF_INVALID; - for (i = 1; *u > utfmax[i]; ++i) - ; - return i; -} - -static size_t -utf8decode(const char *c, long *u, size_t clen) -{ - size_t i, j, len, type; - long udecoded; + static const unsigned char lens[] = { + /* 0XXXX */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + /* 10XXX */ 0, 0, 0, 0, 0, 0, 0, 0, /* invalid */ + /* 110XX */ 2, 2, 2, 2, + /* 1110X */ 3, 3, + /* 11110 */ 4, + /* 11111 */ 0, /* invalid */ + }; + static const unsigned char leading_mask[] = { 0x7F, 0x1F, 0x0F, 0x07 }; + static const unsigned int overlong[] = { 0x0, 0x80, 0x0800, 0x10000 }; + const unsigned char *s = (const unsigned char *)s_in; + int len = lens[*s >> 3]; *u = UTF_INVALID; - if (!clen) - return 0; - udecoded = utf8decodebyte(c[0], &len); - if (!BETWEEN(len, 1, UTF_SIZ)) + *err = 1; + if (len == 0) return 1; - for (i = 1, j = 1; i < clen && j < len; ++i, ++j) { - udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); - if (type) - return j; + + long cp = s[0] & leading_mask[len - 1]; + for (int i = 1; i < len; ++i) { + if (s[i] == '\0' || (s[i] & 0xC0) != 0x80) + return i; + cp = (cp << 6) | (s[i] & 0x3F); } - if (j < len) - return 0; - *u = udecoded; - utf8validate(u, len); + /* out of range, surrogate, overlong encoding */ + if (cp > 0x10FFFF || (cp >> 11) == 0x1B || cp < overlong[len - 1]) + return len; + *err = 0; + *u = cp; return len; } @@ -242,7 +228,7 @@ unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len, hash, h0, h1; XftDraw *d = NULL; Fnt *usedfont, *curfont, *nextfont; - int utf8strlen, utf8charlen, render = x || y || w || h; + int utf8strlen, utf8charlen, utf8err, render = x || y || w || h; long utf8codepoint = 0; const char *utf8str; FcCharSet *fccharset; @@ -251,7 +237,8 @@ XftResult result; int charexists = 0, overflow = 0; /* keep track of a couple codepoints for which we have no match. */ - static unsigned int nomatches[128], ellipsis_width; + static unsigned int nomatches[128], ellipsis_width, invalid_width; + static const char invalid[] = "�"; if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts) return 0; @@ -261,6 +248,8 @@ } else { XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel); XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h); + if (w < lpad) + return x + w; d = XftDrawCreate(drw->dpy, drw->drawable, DefaultVisual(drw->dpy, drw->screen), DefaultColormap(drw->dpy, drw->screen)); @@ -271,12 +260,14 @@ usedfont = drw->fonts; if (!ellipsis_width && render) ellipsis_width = drw_fontset_getwidth(drw, "..."); + if (!invalid_width && render) + invalid_width = drw_fontset_getwidth(drw, invalid); while (1) { - ew = ellipsis_len = utf8strlen = 0; + ew = ellipsis_len = utf8err = utf8charlen = utf8strlen = 0; utf8str = text; nextfont = NULL; while (*text) { - utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ); + utf8charlen = utf8decode(text, &utf8codepoint, &utf8err); for (curfont = drw->fonts; curfont; curfont = curfont->next) { charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint); if (charexists) { @@ -298,9 +289,9 @@ else utf8strlen = ellipsis_len; } else if (curfont == usedfont) { - utf8strlen += utf8charlen; text += utf8charlen; - ew += tmpw; + utf8strlen += utf8err ? 0 : utf8charlen; + ew += utf8err ? 0 : tmpw; } else { nextfont = curfont; } @@ -308,7 +299,7 @@ } } - if (overflow || !charexists || nextfont) + if (overflow || !charexists || nextfont || utf8err) break; else charexists = 0; @@ -323,6 +314,12 @@ x += ew; w -= ew; } + if (utf8err && (!render || invalid_width < w)) { + if (render) + drw_text(drw, x, y, w, h, 0, invalid, invert); + x += invalid_width; + w -= invalid_width; + } if (render && overflow) drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dmenu-5.3/util.c new/dmenu-5.4/util.c --- old/dmenu-5.3/util.c 2024-03-19 12:25:09.000000000 +0100 +++ new/dmenu-5.4/util.c 2025-08-09 15:00:49.950267502 +0200 @@ -1,4 +1,5 @@ /* See LICENSE file for copyright and license details. */ +#include <errno.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -10,17 +11,17 @@ die(const char *fmt, ...) { va_list ap; + int saved_errno; + + saved_errno = errno; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); - if (fmt[0] && fmt[strlen(fmt)-1] == ':') { - fputc(' ', stderr); - perror(NULL); - } else { - fputc('\n', stderr); - } + if (fmt[0] && fmt[strlen(fmt)-1] == ':') + fprintf(stderr, " %s", strerror(saved_errno)); + fputc('\n', stderr); exit(1); }
