libformw: field_buffer() segfaults on a field from dup_field()/link_field()
Serhiy Storchaka <[email protected]> Mon, 3 Aug 2026 14:05:18 +0300
| Newsgroups | gmane.comp.lib.ncurses.bugs |
|---|---|
| Message-ID | <[email protected]> |
field_buffer() dereferences a NULL pointer for any field created by
dup_field() or link_field(), when linked against libformw. The narrow
libform is not affected, and only the read side fails: set_field_buffer()
and post_form() work on such a field, and calling set_field_buffer() first
does not help.
ncurses 6.6.20251231 (Debian libncursesw6 6.6+20251231-1),
Linux 7.0.0 x86_64, gcc 15.2.0.
#include <form.h>
#include <locale.h>
#include <stdio.h>
int
main(void)
{
setlocale(LC_ALL, "");
initscr();
FIELD *orig = new_field(1, 10, 0, 0, 0, 0);
set_field_buffer(orig, 0, "hello");
FIELD *copy = dup_field(orig, 1, 0);
endwin();
printf("orig: %s\n", field_buffer(orig, 0));
printf("dup: %s\n", field_buffer(copy, 0)); /* SIGSEGV here */
return 0;
}
$ gcc $(pkg-config --cflags formw ncursesw) t.c -o t \
$(pkg-config --libs formw ncursesw)
$ ./t
orig: hello
Segmentation fault
#0 field_buffer () from /usr/lib/x86_64-linux-gnu/libformw.so.6
new_field() allocates the per-field rendering state:
fld_def.c:307: New_Field->working = newpad(1,
Buffer_Length(New_Field) + 1);
fld_def.c:308: New_Field->expanded = typeCalloc(char *, 1 +
(unsigned)nbuf);
dup_field() and link_field() start from *_nc_Default_Field, where both are
NULL, and never allocate them. A NULL 'working' is repaired by accident,
since set_field_buffer() reallocates it when wresize() fails
(frm_driver.c:4800-4804), but nothing repairs 'expanded', and field_buffer()
indexes it unconditionally:
frm_driver.c:4900: if (field->expanded[buffer] != NULL)
test/dup_field.c never calls field_buffer() on the duplicated field,
which is
probably why this has gone unnoticed.
No patch, as I cannot tell whether you would rather allocate the state in
dup_field()/link_field() or have field_buffer() allocate it on demand.