Fossil SCM
Defend against a possible infinite loop in forumpost_is_closed() that might occur if the forumpost table contains goofy data.
Commit
923aa7534586349041dbff753293e637411b19cf1dfb37215f18d8d14947578d
Parent
fbd77310b65e0ce…
1 file changed
+14
-5
+14
-5
| --- src/forum.c | ||
| +++ src/forum.c | ||
| @@ -59,10 +59,11 @@ | ||
| 59 | 59 | ForumPost *pFirst; /* First post in chronological order */ |
| 60 | 60 | ForumPost *pLast; /* Last post in chronological order */ |
| 61 | 61 | ForumPost *pDisplay; /* Entries in display order */ |
| 62 | 62 | ForumPost *pTail; /* Last on the display list */ |
| 63 | 63 | int mxIndent; /* Maximum indentation level */ |
| 64 | + int nArtifact; /* Number of forum artifacts in this thread */ | |
| 64 | 65 | }; |
| 65 | 66 | #endif /* INTERFACE */ |
| 66 | 67 | |
| 67 | 68 | /* |
| 68 | 69 | ** Return true if the forum post with the given rid has been |
| @@ -109,12 +110,17 @@ | ||
| 109 | 110 | ** the post. |
| 110 | 111 | ** |
| 111 | 112 | ** If bCheckIrt is true then p's thread in-response-to parents are |
| 112 | 113 | ** checked (recursively) for closure, else only p is checked. |
| 113 | 114 | */ |
| 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 ){ | |
| 116 | 122 | if( p->pEditHead ) p = p->pEditHead; |
| 117 | 123 | if( p->iClosed || !bCheckIrt ) return p->iClosed; |
| 118 | 124 | p = p->pIrt; |
| 119 | 125 | } |
| 120 | 126 | return 0; |
| @@ -409,10 +415,11 @@ | ||
| 409 | 415 | pThread->pFirst = pPost; |
| 410 | 416 | }else{ |
| 411 | 417 | pThread->pLast->pNext = pPost; |
| 412 | 418 | } |
| 413 | 419 | pThread->pLast = pPost; |
| 420 | + pThread->nArtifact++; | |
| 414 | 421 | |
| 415 | 422 | /* Find the in-reply-to post. Default to the topic post if the replied-to |
| 416 | 423 | ** post cannot be found. */ |
| 417 | 424 | if( firt ){ |
| 418 | 425 | pPost->pIrt = pThread->pFirst; |
| @@ -520,10 +527,11 @@ | ||
| 520 | 527 | fossil_fatal("Not a forum post: \"%s\"", zName); |
| 521 | 528 | } |
| 522 | 529 | fossil_print("fpid = %d\n", fpid); |
| 523 | 530 | fossil_print("froot = %d\n", froot); |
| 524 | 531 | pThread = forumthread_create(froot, 1); |
| 532 | + fossil_print("count = %d\n", pThread->nArtifact); | |
| 525 | 533 | fossil_print("Chronological:\n"); |
| 526 | 534 | fossil_print( |
| 527 | 535 | /* 0 1 2 3 4 5 6 7 */ |
| 528 | 536 | /* 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123 */ |
| 529 | 537 | " sid rev closed fpid pIrt pEditPrev pEditTail hash\n"); |
| @@ -725,10 +733,11 @@ | ||
| 725 | 733 | |
| 726 | 734 | /* |
| 727 | 735 | ** Display a single post in a forum thread. |
| 728 | 736 | */ |
| 729 | 737 | static void forum_display_post( |
| 738 | + ForumThread *pThread, /* The thread that this post is a member of */ | |
| 730 | 739 | ForumPost *p, /* Forum post to display */ |
| 731 | 740 | int iIndentScale, /* Indent scale factor */ |
| 732 | 741 | int bRaw, /* True to omit the border */ |
| 733 | 742 | int bUnf, /* True to leave the post unformatted */ |
| 734 | 743 | int bHist, /* True if showing edit history */ |
| @@ -747,14 +756,14 @@ | ||
| 747 | 756 | const char *zMimetype;/* Formatting MIME type */ |
| 748 | 757 | |
| 749 | 758 | /* Get the manifest for the post. Abort if not found (e.g. shunned). */ |
| 750 | 759 | pManifest = manifest_get(p->fpid, CFTYPE_FORUM, 0); |
| 751 | 760 | if( !pManifest ) return; |
| 752 | - iClosed = forumpost_is_closed(p, 1); | |
| 761 | + iClosed = forumpost_is_closed(pThread, p, 1); | |
| 753 | 762 | /* When not in raw mode, create the border around the post. */ |
| 754 | 763 | 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 | |
| 756 | 765 | ** as selected and/or obsolete. */ |
| 757 | 766 | iIndent = (p->pEditHead ? p->pEditHead->nIndent : p->nIndent)-1; |
| 758 | 767 | @ <div id='forum%d(p->fpid)' class='forumTime\ |
| 759 | 768 | @ %s(bSelect ? " forumSel" : "")\ |
| 760 | 769 | @ %s(iClosed ? " forumClosed" : "")\ |
| @@ -1027,11 +1036,11 @@ | ||
| 1027 | 1036 | } |
| 1028 | 1037 | |
| 1029 | 1038 | /* Display the appropriate subset of posts in sequence. */ |
| 1030 | 1039 | while( p ){ |
| 1031 | 1040 | /* Display the post. */ |
| 1032 | - forum_display_post(p, iIndentScale, mode==FD_RAW, | |
| 1041 | + forum_display_post(pThread, p, iIndentScale, mode==FD_RAW, | |
| 1033 | 1042 | bUnf, bHist, p==pSelect, zQuery); |
| 1034 | 1043 | |
| 1035 | 1044 | /* Advance to the next post in the thread. */ |
| 1036 | 1045 | if( mode==FD_CHRONO ){ |
| 1037 | 1046 | /* Chronological mode: display posts (optionally including edits) in their |
| 1038 | 1047 |
| --- 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 |