[git commit] libbb: introduce and use xasprintf_inplace()
Denys Vlasenko
vda.linux at googlemail.com
Thu Feb 5 12:36:27 UTC 2026
commit: https://git.busybox.net/busybox/commit/?id=fddd93edbdbf8c5afbfdb3c01d82e082a8a82d1a
branch: https://git.busybox.net/busybox/log/?h=master
function old new delta
xasprintf_and_free - 49 +49
watch_main 269 282 +13
singlemount 1313 1315 +2
append_mount_options 157 149 -8
ip_port_str 122 112 -10
lsblk_main 869 858 -11
add_cmd 1178 1167 -11
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 2/4 up/down: 64/-40) Total: 24 bytes
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
editors/sed.c | 5 ++---
include/libbb.h | 2 ++
libbb/xfuncs_printf.c | 16 ++++++++++++++++
modutils/modprobe-small.c | 4 +---
networking/ifupdown.c | 5 ++---
networking/netstat.c | 7 +++----
procps/watch.c | 7 ++-----
util-linux/lsblk.c | 11 +++++------
util-linux/mount.c | 25 +++++++++++++++----------
9 files changed, 48 insertions(+), 34 deletions(-)
diff --git a/editors/sed.c b/editors/sed.c
index 6179c5e80..029e9b8e7 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -657,9 +657,8 @@ static void add_cmd(const char *cmdstr)
/* Append this line to any unfinished line from last time. */
if (G.add_cmd_line) {
- char *tp = xasprintf("%s\n%s", G.add_cmd_line, cmdstr);
- free(G.add_cmd_line);
- cmdstr = G.add_cmd_line = tp;
+ cmdstr = xasprintf_inplace(G.add_cmd_line,
+ "%s\n%s", G.add_cmd_line, cmdstr);
}
/* If this line ends with unescaped backslash, request next line. */
diff --git a/include/libbb.h b/include/libbb.h
index 7cca925b9..6ce01ea94 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -950,6 +950,8 @@ int bb_putchar(int ch) FAST_FUNC;
int bb_putchar_stderr(char ch) FAST_FUNC;
int fputs_stdout(const char *s) FAST_FUNC;
char *xasprintf(const char *format, ...) __attribute__ ((format(printf, 1, 2))) FAST_FUNC RETURNS_MALLOC;
+char *xasprintf_and_free(char *allocated, const char *format, ...) __attribute__ ((format(printf, 2, 3))) FAST_FUNC RETURNS_MALLOC;
+#define xasprintf_inplace(allocated, ...) ((allocated) = xasprintf_and_free((allocated), __VA_ARGS__))
char *auto_string(char *str) FAST_FUNC;
// gcc-4.1.1 still isn't good enough at optimizing it
// (+200 bytes compared to macro)
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index 5d26e2bfa..ed10084b3 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -349,6 +349,22 @@ char* FAST_FUNC xasprintf(const char *format, ...)
return string_ptr;
}
+char* FAST_FUNC xasprintf_and_free(char *allocated, const char *format, ...)
+{
+ va_list p;
+ int r;
+ char *string_ptr;
+
+ va_start(p, format);
+ r = vasprintf(&string_ptr, format, p);
+ va_end(p);
+
+ if (r < 0)
+ bb_die_memory_exhausted();
+ free(allocated);
+ return string_ptr;
+}
+
void FAST_FUNC xsetenv(const char *key, const char *value)
{
if (setenv(key, value, 1))
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
index 31a215a29..b3c0768ee 100644
--- a/modutils/modprobe-small.c
+++ b/modutils/modprobe-small.c
@@ -1010,9 +1010,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
char **arg = argv;
while (*++arg) {
/* Enclose options in quotes */
- char *s = options;
- options = xasprintf("%s \"%s\"", s ? s : "", *arg);
- free(s);
+ xasprintf_inplace(options, "%s \"%s\"", options ? options : "", *arg);
*arg = NULL;
}
# else
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 9c3640be7..bc2dca506 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -895,16 +895,15 @@ static struct interfaces_file_t *read_interfaces(const char *filename, struct in
while ((buf = xmalloc_fgetline(f)) != NULL) {
#if ENABLE_DESKTOP
/* Trailing "\" concatenates lines */
+//TODO: check how to handle "line\\" (double backslashes)
char *p;
while ((p = last_char_is(buf, '\\')) != NULL) {
*p = '\0';
rest_of_line = xmalloc_fgetline(f);
if (!rest_of_line)
break;
- p = xasprintf("%s%s", buf, rest_of_line);
- free(buf);
+ xasprintf_inplace(buf, "%s%s", buf, rest_of_line);
free(rest_of_line);
- buf = p;
}
#endif
rest_of_line = buf;
diff --git a/networking/netstat.c b/networking/netstat.c
index 807800a62..d7afa8fdd 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -391,7 +391,7 @@ static const char *get_sname(int port, const char *proto, int numeric)
static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int numeric)
{
- char *host, *host_port;
+ char *host;
/* Code which used "*" for INADDR_ANY is removed: it's ambiguous
* in IPv6, while "0.0.0.0" is not. */
@@ -402,9 +402,8 @@ static char *ip_port_str(struct sockaddr *addr, int port, const char *proto, int
if (!host)
host = xmalloc_sockaddr2dotted_noport(addr);
- host_port = xasprintf("%s:%s", host, get_sname(htons(port), proto, numeric));
- free(host);
- return host_port;
+ xasprintf_inplace(host, "%s:%s", host, get_sname(htons(port), proto, numeric));
+ return host;
}
struct inet_params {
diff --git a/procps/watch.c b/procps/watch.c
index b376fdc33..b828079e5 100644
--- a/procps/watch.c
+++ b/procps/watch.c
@@ -76,12 +76,9 @@ int watch_main(int argc UNUSED_PARAM, char **argv)
// watch ls -l "a /tmp" "2>&1" - ls won't see "a /tmp" as one param.
argv0 = argv;
// If -x, cmd is only used for printing header
- cmd = *argv;
+ cmd = xstrdup(*argv);
while (*++argv)
- cmd = xasprintf("%s %s", cmd, *argv);
-//leaks cmd ^^^
-//TODO: create and use xasprintf_inplace(DST, fmt, args_one_of_which_is_DST)
-//which frees old DST?
+ xasprintf_inplace(cmd, "%s %s", cmd, *argv);
if (opt & (1 << 3))
argv = argv0; // If -x, restore argv[0] to !NULL
diff --git a/util-linux/lsblk.c b/util-linux/lsblk.c
index a482bfbbc..3bd40bcb4 100644
--- a/util-linux/lsblk.c
+++ b/util-linux/lsblk.c
@@ -101,10 +101,10 @@ static char *get_mountpoints(const char *majmin)
mountpoints = NULL;
len = strlen(majmin);
- p = G.mountinfo; // "/proc/self/mountinfo"
+ p = G.mountinfo; // contents of "/proc/self/mountinfo"
/* lines a-la "63 1 259:3 / /MNTPOINT per-mount_options - ext4 /dev/NAME per-superblock_options" */
while (*p) {
- char *e, *f;
+ char *e;
p = skip_non_whitespace(p);
if (*p != ' ') break;
@@ -127,12 +127,11 @@ static char *get_mountpoints(const char *majmin)
// at " /MNTPOINT"
e = skip_non_whitespace(p + 1);
// e is at the end of " /MNTPOINT"
- f = mountpoints;
// NO. We return " /MNT1 /MNT2 /MNT3" _with_ leading space!
-// if (!f)
+// if (!mountpoints)
// p++;
- mountpoints = xasprintf("%s%.*s", f ? f : "", (int)(e - p), p);
- free(f);
+ xasprintf_inplace(mountpoints, "%s%.*s",
+ mountpoints ? mountpoints : "", (int)(e - p), p);
}
return mountpoints;
}
diff --git a/util-linux/mount.c b/util-linux/mount.c
index d0f0ae1ad..d0d109c09 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -556,27 +556,33 @@ static int verbose_mount(const char *source, const char *target,
#endif
// Append mount options to string
+// ("merge two comma-separated lists" is a good candidate for libbb!)
static void append_mount_options(char **oldopts, const char *newopts)
{
if (*oldopts && **oldopts) {
+//TODO: do this unconditionally?
+//this way, newopts of "opt1,opt2,opt1"
+//will be de-duped into "opt1,opt2" in _both_ cases
+//(whether or now old opts are empty)
+//the only modification needed is to not prepend extra comma
+//when old opts is "".
// Do not insert options which are already there
- while (newopts[0]) {
+ while (*newopts) {
char *p;
int len;
+ //if (*newopts == ',') { newopts++; continue; }
len = strchrnul(newopts, ',') - newopts;
p = *oldopts;
while (1) {
- if (!strncmp(p, newopts, len)
+ if (strncmp(p, newopts, len) == 0
&& (p[len] == ',' || p[len] == '\0'))
goto skip;
- p = strchr(p,',');
+ p = strchr(p, ',');
if (!p) break;
p++;
}
- p = xasprintf("%s,%.*s", *oldopts, len, newopts);
- free(*oldopts);
- *oldopts = p;
+ xasprintf_inplace(*oldopts, "%s,%.*s", *oldopts, len, newopts);
skip:
newopts += len;
while (*newopts == ',') newopts++;
@@ -2065,12 +2071,11 @@ static int singlemount(struct mntent *mp, int ignore_busy)
if (!is_prefixed_with(filteropts, ",ip="+1)
&& !strstr(filteropts, ",ip=")
) {
- char *dotted, *ip;
+ char *ip;
// Insert "ip=..." option into options
- dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
+ ip = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
- ip = xasprintf("ip=%s", dotted);
- if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
+ xasprintf_inplace(ip, "ip=%s", ip);
// Note: IPv6 scoped addresses ("host%iface", see RFC 4007) should be
// handled by libc in getnameinfo() (inside xmalloc_sockaddr2dotted_noport()).
// Currently, glibc does not support that (has no NI_NUMERICSCOPE),
More information about the busybox-cvs
mailing list