webalizer fails due to incorrect use of memcpy instead of memmove
Webalizer crashes when used in incremental mode on 3.16.
Here's a minimal config file to reproduce this:
LogType w3c
Incremental yes
HostName blog.majid.info
TimeMe yes
DNSCache dns.cache
DNSChildren 0
and when run:
Warning: Invalid keyword 'DNSCache' (webalizer.conf)
Warning: Invalid keyword 'DNSChildren' (webalizer.conf)
Webalizer V2.23-08 (Linux 5.15.41-0-lts x86_64) English
Using logfile STDIN (w3c)
Creating output in current directory
Hostname for reports is 'blog.majid.info'
History file not found...
Previous run data not found...
Skipping bad record (3220)
...
Skipping bad record (214995)
92.6MiB 0:00:01 [61.4MiB/s] [ <=> ]
Illegal instruction (core dumped)
I build webalizer from source myself and after analyzing the core file in gdb, I found:
Core was generated by `webalizer'.
Program terminated with signal SIGILL, Illegal instruction.
#0 memcpy (__n=<optimized out>, __os=0x55b778bef200 <hist+64>, __od=0x55b778bef1c0 <hist>) at /usr/include/fortify/string.h:50
50 __builtin_trap();
(gdb) bt
#0 memcpy (__n=<optimized out>, __os=0x55b778bef200 <hist+64>, __od=0x55b778bef1c0 <hist>) at /usr/include/fortify/string.h:50
#1 update_history () at preserve.c:280
#2 0x000055b778b7fdd1 in main (argc=<optimized out>, argv=<optimized out>) at webalizer.c:1068
(gdb) fr 1
#1 update_history () at preserve.c:280
280 memcpy(&hist[0],&hist[1],sizeof(hist[0])*i);
The root cause is this line in preserve.c:
memcpy(&hist[0],&hist[1],sizeof(hist[0])*i);
which triggers a Fortify check because memcpy
is not supposed to be used with overlapping memory ranges:
39 _FORTIFY_FN(memcpy) void *memcpy(void *__od, const void *__os, size_t __n)
40 {
41 size_t __bd = __builtin_object_size(__od, 0);
42 size_t __bs = __builtin_object_size(__os, 0);
43 char *__d = (char *)__od;
44 const char *__s = (const char *)__os;
45
46 /* trap if pointers are overlapping but not if dst == src.
47 * gcc seems to like to generate code that relies on dst == src */
48 if ((__d < __s && __d + __n > __s) ||
49 (__s < __d && __s + __n > __d))
50 __builtin_trap();
51 if (__n > __bd || __n > __bs)
52 __builtin_trap();
53 return __builtin_memcpy(__od, __os, __n);
54 }
55
I fixed this in my build by simply running sed -i -e s/memcpy/memmove/g preserve.c
.
Oddly, if compiled -O0
the bug is not triggered.
On an unrelated note, I also needed to add -fcommon
to CFLAGS
as there is some sloppy coding causing shared variables to be redefined in multiple places, at least with a DNS-enabled build.