[BUG] SEGV getop() src/bltin/test.c:171:7

Aleksander Ushakov <[email protected]> Thu, 31 Jul 2025 14:30:00 +0300
Newsgroups org.kernel.vger.dash
Message-ID <[email protected]>
Hello Dash maintainers,

I encountered a bug in Dash in commit b4ef25d7 and would like to report
it. The details are provided below.

AddressSanitizer:DEADLYSIGNAL

=================================================================
==18517==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000a09
(pc 0x58db5c62ec40 bp 0x7ffe4f593610 sp 0x7ffe4f592db0 T0)
==18517==The signal is caused by a READ memory access.
==18517==Hint: address points to the zero page.
       #0 0x58db5c62ec40 in strcmp (/upstream/test/dash/src/dash+0x51c40)
(BuildId: 535a280f2cc73be57729926bfac9fbc4801d63be)
       #1 0x58db5c72ef74 in getop
/upstream/test/dash/src/bltin/test.c:171:7
       #2 0x58db5c72f022 in t_lex
/upstream/test/dash/src/bltin/test.c:444:7
       #3 0x58db5c72f535 in aexpr
/upstream/test/dash/src/bltin/test.c:269:7
       #4 0x58db5c72f199 in oexpr
/upstream/test/dash/src/bltin/test.c:252:10
       #5 0x58db5c72ee30 in testcmd
/upstream/test/dash/src/bltin/test.c:228:9
       #6 0x58db5c6fee10 in evalbltin
/upstream/test/dash/src/eval.c:975:12
       #7 0x58db5c6fc183 in evalcommand
/upstream/test/dash/src/eval.c:923:7
       #8 0x58db5c6fa925 in evaltree /upstream/test/dash/src/eval.c:305:12
       #9 0x58db5c717762 in cmdloop /upstream/test/dash/src/main.c:246:8
       #10 0x58db5c71736f in main /upstream/test/dash/src/main.c:180:3
       #11 0x76be525ad249 in __libc_start_call_main
csu/../sysdeps/nptl/libc_start_call_main.h:58:16
       #12 0x76be525ad304 in __libc_start_main
csu/../csu/libc-start.c:360:3
       #13 0x58db5c6165d0 in _start (/upstream/test/dash/src/dash+0x395d0)
(BuildId: 535a280f2cc73be57729926bfac9fbc4801d63be)
==18517==Register values:
rax = 0x000000005c74e201  rbx = 0x000058db5c74e260  rcx =
0x0000000000000000  rdx = 0x000058db5c74e6a0
rdi = 0x0000000000000a09  rsi = 0x000058db5c74e260  rbp =
0x00007ffe4f593610  rsp = 0x00007ffe4f592db0
    r8 = 0xf9f9f903f9f9f901   r9 = 0x00000b1beb8e1cd4  r10 =
0x00000b1beba13ac2  r11 = 0x00000b1beb8e1cd0
r12 = 0x0000000000000000  r13 = 0x00007ffe4f5941c8  r14 =
0x0000000000000a09  r15 = 0x0000000000000000
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/upstream/test/dash/src/dash+0x51c40)
(BuildId: 535a280f2cc73be57729926bfac9fbc4801d63be) in strcmp
==18517==ABORTING

Environment:

Debian-12, x86-64
clang-19 compiler

Steps to reproduce:

./autogen.sh
CC=clang CFLAGS=" -fsanitize=address -g " ./configure --disable-fnmatch
--disable-lineno --disable-glob
make
cd src
echo -e '0000000000000000000000000000000000000000"$IFS"\ntest "" -a' |
./dash

I think I fixed the problem here:

diff --git a/src/bltin/test.c b/src/bltin/test.c
index 6d844f1..f8caf86 100644
--- a/src/bltin/test.c
+++ b/src/bltin/test.c
@@ -266,10 +266,19 @@ aexpr(enum token n)
           for (;;) {
                   if (!nexpr(n))
                           res = 0;
+
+               if (!t_wp[1])
+                       break;
+
                   n = t_lex(t_wp + 1);
                   if (n != BAND)
                           break;
-               n = t_lex(t_wp += 2);
+
+               if (!t_wp[2]) {
+                       break;
+               }
+               t_wp += 2;
+               n = t_lex(t_wp);
           }
           return res;
    }

This diff fixes the crash in the aexpr() function by adding critical
bounds checking when processing logical AND (-a) operations in the test
command. It first verifies that t_wp[1] exists before attempting to lex
the next token, preventing null pointer dereferences when no more
arguments remain. For AND operations, it additionally checks that
t_wp[2] (the right operand) exists before advancing the pointer and
lexing, ensuring we never access invalid memory locations. The changes
separate the pointer advancement (t_wp += 2) from the lexing operation
(t_lex(t_wp)) for clearer control flow while maintaining the same
functionality, but now safely handling edge cases where arguments might
be missing after operators.