Age | Commit message (Collapse) | Author |
|
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.
|
|
ignore body end markers of lists breaking other blocks.
Fixing a logical error that caused a NULL deref found by tb@ with afl(1).
|
|
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).
|
|
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.
|
|
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...
|
|
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.
|
|
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.
|
|
|
|
|
|
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.
|
|
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).
|
|
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.
|
|
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).
|
|
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@.
|
|
|
|
Bug reported by jsg@.
|
|
* 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.
|
|
* 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.
|
|
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.
|
|
* 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.
|
|
Almost completely mechanical, no functional change.
Written on the train from Exeter to London returning from p2k15.
|
|
the end macro of a broken block, put all of it into the breaking block.
Needed for example by mutella(1).
|
|
Both partial and full implicit blocks can break explicit blocks.
Put the code to handle both cases into a common function.
|
|
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).
|
|
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.
|
|
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.
|
|
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.
|
|
eventually leading to NULL pointer access;
found by jsg@ with afl, text case #455.
|
|
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.
|
|
so if we are in a loop over blocks, cleanly restart the loop
rather than risking use after free; found by jsg@ with afl.
|
|
replacing the last instances by more specific warnings.
Improved functionality, minus 50 lines of code.
|
|
better handle .Fo with more than one argument
|
|
|
|
|
|
Minus one struct member, minus 17 lines of code, no functional change.
|
|
Discard empty .Bk blocks.
Improve related diagnostics.
|
|
|
|
(assertion failure); regression found in jsg@'s afl test case 847.
|
|
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.
|
|
as a bonus, get rid of another call to rew_sub().
|
|
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).
|
|
the calling macro handler already found the breaking block.
No functional change except tiny variations in error messages.
|
|
is known. This only leaves three that do actual searching.
No functional change, minus 30 lines of code.
|
|
remain in other functions. As a bonus, this fixes an assertion failure
jsg@ found some time ago with afl (test case 982) and improves minor
details in error reporting.
|
|
block closure macro it calls, do not attempt to open its body.
This can for example happen for (nonsensical) constructions like
.Fo
.Nm Fc
in the SYNOPSIS. Fixing an assertion failure jsg@ found with afl
some time ago (test case number 731).
|
|
|
|
* Replace calls to rew_sub() with rew_last() - two less out of 18.
* No need to keep track of the body, it's always opened right after
the head and never used for anything in this function.
|
|
and elements under any and all circumstances, even handling some
bad block nesting now and then. Little surprisingly, this ends up
in excessive complexity and has caused many bugs in the past.
Start to slowly disentangle this mess by replacing calls to rew_sub()
immediately following mdoc_head_alloc() by the much simpler rew_last().
Gets rid of the first two rew_sub() calls out of twenty.
No functional change.
|
|
Similarly, avoid having the same block break two other blocks.
In some situations, this could lead to an endless loop in rew_sub()
found by jsg@ with afl.
Minimal example: .Po Ao Pc Bo Pc Ac Bc
|
|
1) rew_sub(): Make sure REWIND_MORE is acted upon even when followed by
REWIND_NONE. This prevents .It from ending up inside other children of .Bl.
2) blk_exp_close(): Only allow extension of .Bl when it has at least
one .It. Otherwise, a broken child block could be moved in front of
the .Bl, effectively resulting in a .Bl that ended before it began.
|