aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/mdoc_macro.c
Commit message (Collapse)AuthorAgeFilesLines
* Fix block scoping error if an explicit block is broken by twoIngo Schwarze2017-02-161-3/+6
| | | | | | | | | implicit blocks (.Aq Bq Po .Pc) that left the outer breaker open and could in exceptional cases, like between .Bl and .It, cause tree corruption leading to NULL dereference. Found by tb@ with afl(1). While here, do not mark intermediate ENDBODY markers as broken.
* Remove the ENDBODY_NOSPACE flag, simplifying the code.Ingo Schwarze2017-02-161-4/+4
| | | | | | | | Comparing to groff output, it appears that all cases where it was used and made a difference actually require the opposite, ENDBODY_SPACE. I have no idea why i added it back in 2010; maybe to compensate for some other bug that has long been fixed.
* Never look for broken blocks inside blocks that are already closed.Ingo Schwarze2017-02-111-4/+5
| | | | | Fixes the last the of tree corruptions sometimes causing NULL dereference reported by tb@; this one triggered in cases like: .Bl -column .It Pq Ta
* Do not prematurely close .Nd containing a broken child.Ingo Schwarze2017-02-111-3/+9
| | | | | | Fixes tree corruption leading to NULL dereference in insane cases like .Oo Oo .Nd .Pq Oc .Oc Oc found by tb@ with afl(1).
* Do not prematurely mark intermediate blocks as broken while scanningIngo Schwarze2017-02-111-10/+17
| | | | | backwards. Only do so when a block is found that is actually broken. Logic error found while investigating crashes reported by tb@.
* For child macros of block-end macros, only scan backwards for pendingIngo Schwarze2017-02-101-7/+8
| | | | | | | | breakers unless the parent of the block is already closed. While the scanning is needed in cases like ".Ac Bo" for broken Ao, it is useless and crashy in cases like ".Ac Bc" for non-broken Ao. This fixes a NULL pointer dereference that tb@ found with afl(1).
* In the SYNOPSIS, .Nm blocks can get broken if one of their childrenIngo Schwarze2017-02-101-7/+15
| | | | | | | | | | | | gets broken. In that case, mark them as BROKEN and ENDED and make sure they get closed out together with the child. Fixes tree corruption leeding to a NULL dereference found by tb@ with afl(1) in: .Sh SYNOPSIS .Bl .Oo .Nm .Bk .Oc .It (where .Bk is the child and .Oo is the breaker). A simpler form of the same corruption (without crash) is visible in: .Sh SYNOPSIS .Ao .Nm .Bo .Ac .Bc text where the text ended up inside the .Nm (child .Bo, breaker .Ao).
* unify names of AST node flags; no change of cpp outputIngo Schwarze2017-01-101-31/+31
|
* When a mismatching end macro occurs while at least two nested blocksIngo Schwarze2016-08-201-14/+23
| | | | | | | | are open, all except the innermost open block got a bogus MDOC_ENDED marker, in some situations triggering segfaults down the road which tb@ found with afl(1). Fix the logic error by figuring out up front whether an end macro has a matching body, and if it hasn't, don't mark any blocks as broken.
* When scanning upwards for a column list to put a .Ta macro in,Ingo Schwarze2016-08-201-2/+2
| | | | | ignore body end markers of lists breaking other blocks. Fixing a logical error that caused a NULL deref found by tb@ with afl(1).
* Even after switching from a pending head to the body, we have toIngo Schwarze2016-08-111-2/+2
| | | | | | continue scanning upwards, because the enclosing block might already be pending as well, e.g. .Bl .Bl .It Bo .El .It. Tree corruption leading to a later NULL deref found by tb@ with afl(1).
* In order to become able to generate syntax tree nodes on the roff(7)Ingo Schwarze2015-10-201-13/+7
| | | | | | | | level, validation must be separated from parsing and rewinding. This first big step moves calling of the mdoc(7) post_*() functions out of the parser loop into their own mdoc_validate() pass, while using a new mdoc_state() module to make syntax tree state handling available to both the parser loop and the validation pass.
* Very tricky diff to fix macro interpretation and spacing around tabsIngo Schwarze2015-10-171-23/+29
| | | | | | | | | | | | | | in .Bl -column; it took me more than a day to get this right. Triggered by a loosely related bug report from tim@. The lesson for you is: Use .Ta macros in .Bl -column, avoid tabs, or you are in for surprises: The last word before a tab is not interpreted as a macro (unless there is a blank in between), the first word after a tab isn't either (unless there is a blank in between), and a blank after a tab causes a leading blank in the respective output cell. Yes, "blank", "tab", "blank tab" and "tab blank" all have different semantics; if you write code relying on that, good luck maintaining it afterwards...
* When blk_full() handles an .It line in .Bl -column and indirectlyIngo Schwarze2015-10-151-1/+6
| | | | | | | | calls phrase_ta() to handle a .Ta child macro, advance the body pointer accordingly, such that a subsequent tab character rewinds the right body block and doesn't fail an assertion. That happened when there was nothing between the .Ta and the tab character. Bug reported by tim@ some time ago.
* To make the code more readable, delete 283 /* FALLTHROUGH */ commentsIngo Schwarze2015-10-121-11/+1
| | | | | | that were right between two adjacent case statement. Keep only those 24 where the first case actually executes some code before falling through to the next case.
* modernize style: "return" is not a functionIngo Schwarze2015-10-061-25/+25
|
* /* NOTREACHED */ after abort() is silly, delete itIngo Schwarze2015-09-261-2/+1
|
* mdoc_valid_post() may indirectly call roff_node_unlink() which mayIngo Schwarze2015-05-011-2/+2
| | | | | | | | | | | set ROFF_NEXT_CHILD, which is desirable for the final call to mdoc_valid_post() - in case the target itself gets deleted, the parse point may need this adjustment - but not for the intermediate calls - if intermediate nodes get deleted, that mustn't clobber the parse point. So move setting ROFF_NEXT_SIBLING to the proper place in rew_last(). This fixes the assertion failure in jsg@'s afl test case 108/Apr27.
* Setting the "last" member of struct roff_node was done at an extremelyIngo Schwarze2015-05-011-4/+2
| | | | | | | | weird place. Move it to the obviously correct place. Surprisingly, this didn't cause any misformatting in the test suite or in any base system manuals, but i cannot believe the code was really correct for all conceivable input, and it would be very hard to verify. At the very least, it cannot have worked for man(7).
* Minor bug fix: When .Pp rewinds .Nm, rewind the whole block,Ingo Schwarze2015-05-011-2/+2
| | | | | not just the body. In some unusual edge cases, this caused the .Pp to become a sibling of the .Nm body inside the .Nm block.
* If a block body gets broken, that's no good reason to extend theIngo Schwarze2015-04-291-2/+4
| | | | | | | scope of the end macro. Instead, only keep the tail scope open if the end macro macro calls an explicit macro and actually breaks that. This corrects syntax tree structure and fixes an assertion found by jsg@ with afl (test case 098/Apr27).
* Do not mark a block with the MDOC_BROKEN flag if it merely containsIngo Schwarze2015-04-291-1/+3
| | | | | | a mismatching explicit end macro without actually being broken. Avoids a subsequent upward search for the non-existent breaker ending up in a NULL pointer access; afl test case 005/Apr27 from jsg@.
* Get rid of two empty wrapper functions. No functional change.Ingo Schwarze2015-04-231-2/+2
|
* Avoid a use after free when the target node is deleted during validation.Ingo Schwarze2015-04-211-13/+16
| | | | Bug reported by jsg@.
* Unify trickier node handling functions.Ingo Schwarze2015-04-191-4/+4
| | | | | | | * man_elem_alloc() -> roff_elem_alloc() * man_block_alloc() -> roff_block_alloc() The functions mdoc_elem_alloc() and mdoc_block_alloc() remain for now because they need to do mdoc(7)-specific argument processing.
* Unify some node handling functions that use TOKEN_NONE.Ingo Schwarze2015-04-191-3/+3
| | | | | | | | * mdoc_word_alloc(), man_word_alloc() -> roff_word_alloc() * mdoc_word_append(), man_word_append() -> roff_word_append() * mdoc_addspan(), man_addspan() -> roff_addtbl() * mdoc_addeqn(), man_addeqn() -> roff_addeqn() Minus 50 lines of code, no functional change.
* Decouple the token code for "no request or macro" from the individualIngo Schwarze2015-04-191-18/+19
| | | | | | high-level parsers to allow further unification of functions that only need to recognize this code, but that don't care about different high-level macrosets beyond that.
* Unify node handling functions:Ingo Schwarze2015-04-191-17/+18
| | | | | | | | | | | * node_alloc() for mdoc and man_node_alloc() -> roff_node_alloc() * node_append() for mdoc and man_node_append() -> roff_node_append() * mdoc_head_alloc() and man_head_alloc() -> roff_head_alloc() * mdoc_body_alloc() and man_body_alloc() -> roff_body_alloc() * mdoc_node_unlink() and man_node_unlink() -> roff_node_unlink() * mdoc_node_free() and man_node_free() -> roff_node_free() * mdoc_node_delete() and man_node_delete() -> roff_node_delete() Minus 130 lines of code, no functional change.
* Replace the structs mdoc and man by a unified struct roff_man.Ingo Schwarze2015-04-181-21/+22
| | | | | Almost completely mechanical, no functional change. Written on the train from Exeter to London returning from p2k15.
* If a partial explicit block extending to the next input line followsIngo Schwarze2015-04-051-4/+16
| | | | | the end macro of a broken block, put all of it into the breaking block. Needed for example by mutella(1).
* Reduce code duplication, no functional change:Ingo Schwarze2015-04-051-51/+45
| | | | | Both partial and full implicit blocks can break explicit blocks. Put the code to handle both cases into a common function.
* Arguments to end macros of broken partial explicit blocksIngo Schwarze2015-04-051-10/+8
| | | | | | | | must go inside the breaking block. For example, in .It Ic cmd Oo .Ar optional_arg Oc Ar mandatory_arg the mandatory_arg is still inside the .It block. Used for example by mutella(1).
* Second step towards parser unification:Ingo Schwarze2015-04-021-40/+38
| | | | | | | | | Replace struct mdoc_node and struct man_node by a unified struct roff_node. To be able to use the tok member for both mdoc(7) and man(7) without defining all the macros in roff.h, sacrifice a tiny bit of type safety and make tok an int rather than an enum. Almost mechanical, no functional change. Written on the Eurostar from Bruxelles to London on the way to p2k15.
* First step towards parser unification:Ingo Schwarze2015-04-021-20/+21
| | | | | | Replace enum mdoc_type and enum man_type by a unified enum roff_type. Almost mechanical, no functional change. Written on the ICE train from Frankfurt to Bruxelles on the way to p2k15.
* Delete the mdoc_node.pending pointer and the function calculatingIngo Schwarze2015-02-121-110/+78
| | | | | | | | | | | | | | | | | | | | | | | it, make_pending(), which was the most difficult function of the whole mdoc(7) parser. After almost five years of maintaining this hellhole, i just noticed the pointer isn't needed after all. Blocks are always rewound in the reverse order they were opened; that even holds for broken blocks. Consequently, it is sufficient to just mark broken blogs with the flag MDOC_BROKEN and breaking blocks with the flag MDOC_ENDED. When rewinding, instead of iterating the pending pointers, just iterate from each broken block to its parents, rewinding all that are MDOC_ENDED and stopping after processing the first ancestor that it not MDOC_BROKEN. For ENDBODY markers, use the mdoc_node.body pointer in place of the former mdoc_node.pending. This also fixes an assertion failure found by jsg@ with afl, test case #467 (Bo Bl It Bd Bc It), where (surprise surprise) the pending pointer got corrupted. Improved functionality, minus one function, minus one struct field, minus 50 lines of code.
* explicit blocks close out .Nd; fixing data structure corruptionIngo Schwarze2015-02-111-1/+8
| | | | | eventually leading to NULL pointer access; found by jsg@ with afl, text case #455.
* Be more careful to not generate empty .In, .St, and .Xr nodes.Ingo Schwarze2015-02-101-34/+44
| | | | | | | | That could happen when their first argument was another called macro, causing a NULL pointer access in .St validation found by jsg@ with afl. Make in_line_argn() easier to understand by using one state variable rather than two.
* Closing a block validates it, which may end up deleting it,Ingo Schwarze2015-02-071-1/+2
| | | | | so if we are in a loop over blocks, cleanly restart the loop rather than risking use after free; found by jsg@ with afl.
* Delete the legacy generic warning type MANDOCERR_ARGCWARN,Ingo Schwarze2015-02-061-3/+4
| | | | | replacing the last instances by more specific warnings. Improved functionality, minus 50 lines of code.
* better handle .Fo and .Fd without argumentIngo Schwarze2015-02-061-1/+7
| | | | better handle .Fo with more than one argument
* better handle .In .Sh .Ss .St .Xr without argumentsIngo Schwarze2015-02-061-1/+12
|
* fix handling of empty .An macrosIngo Schwarze2015-02-051-2/+2
|
* Simplify by deleting the "lastline" member of struct mdoc_node.Ingo Schwarze2015-02-051-8/+2
| | | | Minus one struct member, minus 17 lines of code, no functional change.
* Discard excess head arguments for .Bd .Bl .Bk and delete hwarn_eq0().Ingo Schwarze2015-02-041-2/+8
| | | | | Discard empty .Bk blocks. Improve related diagnostics.
* discard .Rs head arguments and improve .Rs diagnosticsIngo Schwarze2015-02-041-4/+9
|
* Avoid closing out an explicit block twice when broken by .ItIngo Schwarze2015-02-031-1/+2
| | | | (assertion failure); regression found in jsg@'s afl test case 847.
* Finally delete the kitchensink functions rew_sub() and rew_dohalt().Ingo Schwarze2015-02-031-160/+75
| | | | | | | They were a maintenance and auditing nightmare because if you changed one bit in there, stuff tended to break at seemingly unrelated places. No functional change except getting rid of one bogus error message, but minus 80 lines of code.
* Bring .Pp/.Lp handling inside .Nm blocks closer to groff;Ingo Schwarze2015-02-031-4/+11
| | | | as a bonus, get rid of another call to rew_sub().
* Simplify and reindent make_pending(). No functional changeIngo Schwarze2015-02-021-57/+50
| | | | | | except that some error messages become less confusing. Now the function is almost readable (but still requires nineteen lines of comments for fourteen lines of code).
* Simplify: Do not call rew_dohalt() from make_pending(),Ingo Schwarze2015-02-021-31/+21
| | | | | the calling macro handler already found the breaking block. No functional change except tiny variations in error messages.