RCS log gets up to large numbers of revisions then RCS will core dump
haoming chu <[email protected]> Wed, 26 Oct 2016 15:07:57 +0800
| Newsgroups | gmane.comp.version-control.rcs.bugs |
|---|---|
| Organization | Oracle Corporation |
| Message-ID | <[email protected]> |
RCS has a known bug which when an RCS log gets up to large numbers of
revisions then RCS will core dump. We have seen this when the RCS log
gets upwards of 80-90,000 entries. RCS will continue to core dump on any
command(co,ci) until the log file is truncated, which is the only
workaround for this issue. The only time we have seen this is in an
error state from a program which is updating a file consistently over
time due to a bug.
for example:
In rcs-5.7-37.el6.x86_64.rpm in CentOS 6.5
# ci -l ./ifcfg-bond3
./RCS/ifcfg-bond3,v <-- ./ifcfg-bond3
Segmentation fault (core dumped)
We found that root cause is:
Infinite recursion without cut-off conditions was used in function
'puttree' in 'rcsgen.c'(line: 553).
So stack collapsed when too many entries in rcs log file.
(ifcfg-bond3,v in attach.tar.gz).
void
puttree(root, fout)
struct hshentry const *root;
register FILE *fout;
/* Output the delta tree with base ROOT in preorder to FOUT. */
{
struct branchhead const *nextbranch;
if (!root) return;
if (root->selector)
putdelta(root, fout);
puttree(root->next, fout);
nextbranch = root->branches;
while (nextbranch) {
puttree(nextbranch->hsh, fout);
nextbranch = nextbranch->nextbranch;
}
}
We make a patch (rcs-5.7-37.patch) to workround this problem in
rcs-5.7-37.el6.x86_64.
(Replace recursion with iteration of the loop.)
rcs-5.7-37.patch
(text/plain, 6.2 KB)
diff -ruNa /root/rcs-5.7/src/rcsbase.h ./rcs-5.7/src/rcsbase.h
--- /root/rcs-5.7/src/rcsbase.h 1995-06-16 02:19:24.000000000 -0400
+++ ./rcs-5.7/src/rcsbase.h 2015-12-28 00:06:08.290116532 -0500
@@ -188,7 +188,6 @@
#include "conf.h"
-
#define EXIT_TROUBLE DIFF_TROUBLE
#ifdef _POSIX_PATH_MAX
@@ -234,6 +233,7 @@
#define true 1
#define false 0
+#define STACK_INC_SIZE 8589934592 /* 8192 * 1024 * 1024 */
/*
* RILE - readonly file
@@ -359,10 +359,10 @@
char const * state; /* state of revision (Exp by default) */
char const * name; /* name (if any) by which retrieved */
struct cbuf log; /* log message requested at checkin */
- struct branchhead * branches; /* list of first revisions on branches*/
+ struct branchhead * branches; /* list of first revisions on branches*/
struct cbuf ig; /* ignored phrases in admin part */
struct cbuf igtext; /* ignored phrases in deltatext part */
- struct hshentry * next; /* next revision on same branch */
+ struct hshentry * next; /* next revision on same branch */
struct hshentry * nexthsh; /* next revision with same hash value */
long insertlns;/* lines inserted (computed by rlog) */
long deletelns;/* lines deleted (computed by rlog) */
@@ -371,8 +371,8 @@
/* list of hash entries */
struct hshentries {
- struct hshentries *rest;
- struct hshentry *first;
+ struct hshentries * rest;
+ struct hshentry * first;
};
/* list element for branch lists */
@@ -383,14 +383,14 @@
/* accesslist element */
struct access {
- char const * login;
- struct access * nextaccess;
+ char const * login;
+ struct access * nextaccess;
};
/* list element for locks */
struct rcslock {
- char const * login;
- struct hshentry * delta;
+ char const * login;
+ struct hshentry * delta;
struct rcslock * nextlock;
};
@@ -401,6 +401,13 @@
struct assoc * nextassoc;
};
+/* point stack */
+struct stack
+{
+ void **base;
+ void **top;
+ size_t stacksize;
+};
#define mainArgs (argc,argv) int argc; char **argv;
@@ -422,7 +429,7 @@
#define IDH "Id"
#define LOCKER "Locker"
#define LOG "Log"
-#define NAME "Name"
+#define NAME "Name"
#define RCSFILE "RCSfile"
#define REVISION "Revision"
#define SOURCE "Source"
diff -ruNa /root/rcs-5.7/src/rcsgen.c ./rcs-5.7/src/rcsgen.c
--- /root/rcs-5.7/src/rcsgen.c 1995-06-16 02:19:24.000000000 -0400
+++ ./rcs-5.7/src/rcsgen.c 2015-12-28 00:06:06.512116495 -0500
@@ -136,9 +136,6 @@
* corrected type of variables assigned to by getc (char --> int)
*/
-
-
-
#include "rcsbase.h"
libId(genId, "$Id: rcsgen.c,v 5.16 1995/06/16 06:19:24 eggert Exp $")
@@ -526,7 +523,7 @@
static void
putdelta(node, fout)
register struct hshentry const *node;
- register FILE * fout;
+ register FILE *fout;
/* Output the delta NODE to FOUT. */
{
struct branchhead const *nextbranch;
@@ -549,6 +546,98 @@
awrite(node->ig.string, node->ig.size, fout);
}
+ static void
+init(pstack)
+ register struct stack *pstack;
+/* Init stack. */
+{
+ pstack->stacksize = (size_t)(STACK_INC_SIZE);
+ if ((pstack->base = malloc(pstack->stacksize)) == NULL)
+ {
+ error("Stack init error!");
+ exit(-1);
+ }
+ pstack->top = pstack->base;
+}
+
+ static void
+destroy(pstack)
+ register struct stack *pstack;
+/* Destroy stack. */
+{
+ if (pstack->base)
+ free(pstack->base);
+ pstack->base = NULL;
+ pstack->top = NULL;
+ pstack->stacksize = 0;
+}
+
+ static int
+push(pstack, element)
+ register struct stack *pstack;
+ register void **element;
+/* Push element to top of stack. */
+{
+ void **temp = NULL;
+
+ if (pstack->top - pstack->base >= pstack->stacksize) {
+ temp = realloc(pstack->base,
+ pstack->stacksize + (size_t)(STACK_INC_SIZE));
+ if (!temp) {
+ error("Stack in heap cannot extend!");
+ return false;
+ }
+
+ if (temp != pstack->base) {
+ pstack->top = temp + (pstack->top - pstack->base);
+ pstack->base = temp;
+ }
+
+ pstack->stacksize += (size_t)(STACK_INC_SIZE);
+ }
+
+ *(pstack->top) = *element;
+ pstack->top++;
+
+ return true;
+}
+
+ static int
+pop(pstack, element)
+ register struct stack *pstack;
+ register void **element;
+/* Pop top element from stack. */
+{
+ if (pstack->top == pstack->base) {
+ error("Stack is empty!");
+ return false;
+ }
+
+ pstack->top--;
+ *element = *(pstack->top);
+
+ return true;
+}
+
+ static void*
+top(pstack)
+ register struct stack *pstack;
+/* Get top element from stack. */
+{
+ if (pstack->top > pstack->base) {
+ return *(pstack->top - 1);
+ }
+ else
+ return NULL;
+}
+
+ static int
+is_empty(pstack)
+ register struct stack *pstack;
+/* To judge whether the stack is empty. */
+{
+ return (pstack->top == pstack->base);
+}
void
puttree(root, fout)
@@ -556,20 +645,49 @@
register FILE *fout;
/* Output the delta tree with base ROOT in preorder to FOUT. */
{
- struct branchhead const *nextbranch;
-
- if (!root) return;
-
- if (root->selector)
- putdelta(root, fout);
-
- puttree(root->next, fout);
+ struct hshentry *node = NULL;
+ struct branchhead const *nextbranch;
+ struct stack pstack = { 0 };
+
+ if (!root)
+ return;
+
+ init(&pstack);
+
+ if (!push(&pstack, &root)) {
+ exit(-1);
+ }
+
+ while (!is_empty(&pstack)) {
+ if (!pop(&pstack, &node)) {
+ exit(-1);
+ }
+
+ if (node) {
+ if (node->selector)
+ putdelta(node, fout);
+
+ if (node->branches) {
+ for (nextbranch = node->branches;
+ nextbranch;
+ nextbranch = nextbranch->nextbranch)
+ if (!push(&pstack, &(nextbranch->hsh))) {
+ exit(-1);
+ }
+ }
+
+ if (node->next) {
+ if (!push(&pstack, &(node->next))) {
+ exit(-1);
+ }
+ }
+ }
+ else {
+ error("Node is empty!");
+ }
+ }
- nextbranch = root->branches;
- while (nextbranch) {
- puttree(nextbranch->hsh, fout);
- nextbranch = nextbranch->nextbranch;
- }
+ destroy(&pstack);
}
attach.tar.gz
(application/gzip, 736.8 KB) - not displayed