Fossil SCM

Defend against a possible infinite loop in forumpost_is_closed() that might occur if the forumpost table contains goofy data.

drh 2025-04-17 23:17 trunk
Commit 923aa7534586349041dbff753293e637411b19cf1dfb37215f18d8d14947578d
1 file changed +14 -5
+14 -5
--- src/forum.c
+++ src/forum.c
@@ -59,10 +59,11 @@
5959
ForumPost *pFirst; /* First post in chronological order */
6060
ForumPost *pLast; /* Last post in chronological order */
6161
ForumPost *pDisplay; /* Entries in display order */
6262
ForumPost *pTail; /* Last on the display list */
6363
int mxIndent; /* Maximum indentation level */
64
+ int nArtifact; /* Number of forum artifacts in this thread */
6465
};
6566
#endif /* INTERFACE */
6667
6768
/*
6869
** Return true if the forum post with the given rid has been
@@ -109,12 +110,17 @@
109110
** the post.
110111
**
111112
** If bCheckIrt is true then p's thread in-response-to parents are
112113
** checked (recursively) for closure, else only p is checked.
113114
*/
114
-static int forumpost_is_closed(ForumPost *p, int bCheckIrt){
115
- while(p){
115
+static int forumpost_is_closed(
116
+ ForumThread *pThread, /* Thread that the post is a member of */
117
+ ForumPost *p, /* the forum post */
118
+ int bCheckIrt /* True to check In-Reply-To posts */
119
+){
120
+ int mx = pThread->nArtifact+1;
121
+ while( p && (mx--)>0 ){
116122
if( p->pEditHead ) p = p->pEditHead;
117123
if( p->iClosed || !bCheckIrt ) return p->iClosed;
118124
p = p->pIrt;
119125
}
120126
return 0;
@@ -409,10 +415,11 @@
409415
pThread->pFirst = pPost;
410416
}else{
411417
pThread->pLast->pNext = pPost;
412418
}
413419
pThread->pLast = pPost;
420
+ pThread->nArtifact++;
414421
415422
/* Find the in-reply-to post. Default to the topic post if the replied-to
416423
** post cannot be found. */
417424
if( firt ){
418425
pPost->pIrt = pThread->pFirst;
@@ -520,10 +527,11 @@
520527
fossil_fatal("Not a forum post: \"%s\"", zName);
521528
}
522529
fossil_print("fpid = %d\n", fpid);
523530
fossil_print("froot = %d\n", froot);
524531
pThread = forumthread_create(froot, 1);
532
+ fossil_print("count = %d\n", pThread->nArtifact);
525533
fossil_print("Chronological:\n");
526534
fossil_print(
527535
/* 0 1 2 3 4 5 6 7 */
528536
/* 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 */
529537
" sid rev closed fpid pIrt pEditPrev pEditTail hash\n");
@@ -725,10 +733,11 @@
725733
726734
/*
727735
** Display a single post in a forum thread.
728736
*/
729737
static void forum_display_post(
738
+ ForumThread *pThread, /* The thread that this post is a member of */
730739
ForumPost *p, /* Forum post to display */
731740
int iIndentScale, /* Indent scale factor */
732741
int bRaw, /* True to omit the border */
733742
int bUnf, /* True to leave the post unformatted */
734743
int bHist, /* True if showing edit history */
@@ -747,14 +756,14 @@
747756
const char *zMimetype;/* Formatting MIME type */
748757
749758
/* Get the manifest for the post. Abort if not found (e.g. shunned). */
750759
pManifest = manifest_get(p->fpid, CFTYPE_FORUM, 0);
751760
if( !pManifest ) return;
752
- iClosed = forumpost_is_closed(p, 1);
761
+ iClosed = forumpost_is_closed(pThread, p, 1);
753762
/* When not in raw mode, create the border around the post. */
754763
if( !bRaw ){
755
- /* Open the <div> enclosing the post. Set the class string to mark the post
764
+ /* Open the <div> enclosing the post. Set the class string to mark the post
756765
** as selected and/or obsolete. */
757766
iIndent = (p->pEditHead ? p->pEditHead->nIndent : p->nIndent)-1;
758767
@ <div id='forum%d(p->fpid)' class='forumTime\
759768
@ %s(bSelect ? " forumSel" : "")\
760769
@ %s(iClosed ? " forumClosed" : "")\
@@ -1027,11 +1036,11 @@
10271036
}
10281037
10291038
/* Display the appropriate subset of posts in sequence. */
10301039
while( p ){
10311040
/* Display the post. */
1032
- forum_display_post(p, iIndentScale, mode==FD_RAW,
1041
+ forum_display_post(pThread, p, iIndentScale, mode==FD_RAW,
10331042
bUnf, bHist, p==pSelect, zQuery);
10341043
10351044
/* Advance to the next post in the thread. */
10361045
if( mode==FD_CHRONO ){
10371046
/* Chronological mode: display posts (optionally including edits) in their
10381047
--- src/forum.c
+++ src/forum.c
@@ -59,10 +59,11 @@
59 ForumPost *pFirst; /* First post in chronological order */
60 ForumPost *pLast; /* Last post in chronological order */
61 ForumPost *pDisplay; /* Entries in display order */
62 ForumPost *pTail; /* Last on the display list */
63 int mxIndent; /* Maximum indentation level */
 
64 };
65 #endif /* INTERFACE */
66
67 /*
68 ** Return true if the forum post with the given rid has been
@@ -109,12 +110,17 @@
109 ** the post.
110 **
111 ** If bCheckIrt is true then p's thread in-response-to parents are
112 ** checked (recursively) for closure, else only p is checked.
113 */
114 static int forumpost_is_closed(ForumPost *p, int bCheckIrt){
115 while(p){
 
 
 
 
 
116 if( p->pEditHead ) p = p->pEditHead;
117 if( p->iClosed || !bCheckIrt ) return p->iClosed;
118 p = p->pIrt;
119 }
120 return 0;
@@ -409,10 +415,11 @@
409 pThread->pFirst = pPost;
410 }else{
411 pThread->pLast->pNext = pPost;
412 }
413 pThread->pLast = pPost;
 
414
415 /* Find the in-reply-to post. Default to the topic post if the replied-to
416 ** post cannot be found. */
417 if( firt ){
418 pPost->pIrt = pThread->pFirst;
@@ -520,10 +527,11 @@
520 fossil_fatal("Not a forum post: \"%s\"", zName);
521 }
522 fossil_print("fpid = %d\n", fpid);
523 fossil_print("froot = %d\n", froot);
524 pThread = forumthread_create(froot, 1);
 
525 fossil_print("Chronological:\n");
526 fossil_print(
527 /* 0 1 2 3 4 5 6 7 */
528 /* 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 */
529 " sid rev closed fpid pIrt pEditPrev pEditTail hash\n");
@@ -725,10 +733,11 @@
725
726 /*
727 ** Display a single post in a forum thread.
728 */
729 static void forum_display_post(
 
730 ForumPost *p, /* Forum post to display */
731 int iIndentScale, /* Indent scale factor */
732 int bRaw, /* True to omit the border */
733 int bUnf, /* True to leave the post unformatted */
734 int bHist, /* True if showing edit history */
@@ -747,14 +756,14 @@
747 const char *zMimetype;/* Formatting MIME type */
748
749 /* Get the manifest for the post. Abort if not found (e.g. shunned). */
750 pManifest = manifest_get(p->fpid, CFTYPE_FORUM, 0);
751 if( !pManifest ) return;
752 iClosed = forumpost_is_closed(p, 1);
753 /* When not in raw mode, create the border around the post. */
754 if( !bRaw ){
755 /* Open the <div> enclosing the post. Set the class string to mark the post
756 ** as selected and/or obsolete. */
757 iIndent = (p->pEditHead ? p->pEditHead->nIndent : p->nIndent)-1;
758 @ <div id='forum%d(p->fpid)' class='forumTime\
759 @ %s(bSelect ? " forumSel" : "")\
760 @ %s(iClosed ? " forumClosed" : "")\
@@ -1027,11 +1036,11 @@
1027 }
1028
1029 /* Display the appropriate subset of posts in sequence. */
1030 while( p ){
1031 /* Display the post. */
1032 forum_display_post(p, iIndentScale, mode==FD_RAW,
1033 bUnf, bHist, p==pSelect, zQuery);
1034
1035 /* Advance to the next post in the thread. */
1036 if( mode==FD_CHRONO ){
1037 /* Chronological mode: display posts (optionally including edits) in their
1038
--- src/forum.c
+++ src/forum.c
@@ -59,10 +59,11 @@
59 ForumPost *pFirst; /* First post in chronological order */
60 ForumPost *pLast; /* Last post in chronological order */
61 ForumPost *pDisplay; /* Entries in display order */
62 ForumPost *pTail; /* Last on the display list */
63 int mxIndent; /* Maximum indentation level */
64 int nArtifact; /* Number of forum artifacts in this thread */
65 };
66 #endif /* INTERFACE */
67
68 /*
69 ** Return true if the forum post with the given rid has been
@@ -109,12 +110,17 @@
110 ** the post.
111 **
112 ** If bCheckIrt is true then p's thread in-response-to parents are
113 ** checked (recursively) for closure, else only p is checked.
114 */
115 static int forumpost_is_closed(
116 ForumThread *pThread, /* Thread that the post is a member of */
117 ForumPost *p, /* the forum post */
118 int bCheckIrt /* True to check In-Reply-To posts */
119 ){
120 int mx = pThread->nArtifact+1;
121 while( p && (mx--)>0 ){
122 if( p->pEditHead ) p = p->pEditHead;
123 if( p->iClosed || !bCheckIrt ) return p->iClosed;
124 p = p->pIrt;
125 }
126 return 0;
@@ -409,10 +415,11 @@
415 pThread->pFirst = pPost;
416 }else{
417 pThread->pLast->pNext = pPost;
418 }
419 pThread->pLast = pPost;
420 pThread->nArtifact++;
421
422 /* Find the in-reply-to post. Default to the topic post if the replied-to
423 ** post cannot be found. */
424 if( firt ){
425 pPost->pIrt = pThread->pFirst;
@@ -520,10 +527,11 @@
527 fossil_fatal("Not a forum post: \"%s\"", zName);
528 }
529 fossil_print("fpid = %d\n", fpid);
530 fossil_print("froot = %d\n", froot);
531 pThread = forumthread_create(froot, 1);
532 fossil_print("count = %d\n", pThread->nArtifact);
533 fossil_print("Chronological:\n");
534 fossil_print(
535 /* 0 1 2 3 4 5 6 7 */
536 /* 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 */
537 " sid rev closed fpid pIrt pEditPrev pEditTail hash\n");
@@ -725,10 +733,11 @@
733
734 /*
735 ** Display a single post in a forum thread.
736 */
737 static void forum_display_post(
738 ForumThread *pThread, /* The thread that this post is a member of */
739 ForumPost *p, /* Forum post to display */
740 int iIndentScale, /* Indent scale factor */
741 int bRaw, /* True to omit the border */
742 int bUnf, /* True to leave the post unformatted */
743 int bHist, /* True if showing edit history */
@@ -747,14 +756,14 @@
756 const char *zMimetype;/* Formatting MIME type */
757
758 /* Get the manifest for the post. Abort if not found (e.g. shunned). */
759 pManifest = manifest_get(p->fpid, CFTYPE_FORUM, 0);
760 if( !pManifest ) return;
761 iClosed = forumpost_is_closed(pThread, p, 1);
762 /* When not in raw mode, create the border around the post. */
763 if( !bRaw ){
764 /* Open the <div> enclosing the post. Set the class string to mark the post
765 ** as selected and/or obsolete. */
766 iIndent = (p->pEditHead ? p->pEditHead->nIndent : p->nIndent)-1;
767 @ <div id='forum%d(p->fpid)' class='forumTime\
768 @ %s(bSelect ? " forumSel" : "")\
769 @ %s(iClosed ? " forumClosed" : "")\
@@ -1027,11 +1036,11 @@
1036 }
1037
1038 /* Display the appropriate subset of posts in sequence. */
1039 while( p ){
1040 /* Display the post. */
1041 forum_display_post(pThread, p, iIndentScale, mode==FD_RAW,
1042 bUnf, bHist, p==pSelect, zQuery);
1043
1044 /* Advance to the next post in the thread. */
1045 if( mode==FD_CHRONO ){
1046 /* Chronological mode: display posts (optionally including edits) in their
1047

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button