mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-17 22:32:51 +00:00
Bug 1083913: Column spans are restricted to 31-bit, not 24-bit, signed values. r=shu
This also cleans up the column span / offset conversions, and fixes some comments.
This commit is contained in:
parent
f5e193968c
commit
155ef09737
js/src
@ -466,17 +466,14 @@ UpdateSourceCoordNotes(ExclusiveContext *cx, BytecodeEmitter *bce, uint32_t offs
|
||||
uint32_t columnIndex = bce->parser->tokenStream.srcCoords.columnIndex(offset);
|
||||
ptrdiff_t colspan = ptrdiff_t(columnIndex) - ptrdiff_t(bce->current->lastColumn);
|
||||
if (colspan != 0) {
|
||||
if (colspan < 0) {
|
||||
colspan += SN_COLSPAN_DOMAIN;
|
||||
} else if (colspan >= SN_COLSPAN_DOMAIN / 2) {
|
||||
// If the column span is so large that we can't store it, then just
|
||||
// discard this information because column information would most
|
||||
// likely be useless anyway once the column numbers are ~4000000.
|
||||
// This has been known to happen with scripts that have been
|
||||
// minimized and put into all one line.
|
||||
// If the column span is so large that we can't store it, then just
|
||||
// discard this information. This can happen with minimized or otherwise
|
||||
// machine-generated code. Even gigantic column numbers are still
|
||||
// valuable if you have a source map to relate them to something real;
|
||||
// but it's better to fail soft here.
|
||||
if (!SN_REPRESENTABLE_COLSPAN(colspan))
|
||||
return true;
|
||||
}
|
||||
if (NewSrcNote2(cx, bce, SRC_COLSPAN, colspan) < 0)
|
||||
if (NewSrcNote2(cx, bce, SRC_COLSPAN, SN_COLSPAN_TO_OFFSET(colspan)) < 0)
|
||||
return false;
|
||||
bce->current->lastColumn = columnIndex;
|
||||
}
|
||||
@ -7294,7 +7291,7 @@ static bool
|
||||
SetSrcNoteOffset(ExclusiveContext *cx, BytecodeEmitter *bce, unsigned index, unsigned which,
|
||||
ptrdiff_t offset)
|
||||
{
|
||||
if (size_t(offset) > SN_MAX_OFFSET) {
|
||||
if (!SN_REPRESENTABLE_OFFSET(offset)) {
|
||||
ReportStatementTooLarge(bce->parser->tokenStream, bce->topStmt);
|
||||
return false;
|
||||
}
|
||||
@ -7311,14 +7308,14 @@ SetSrcNoteOffset(ExclusiveContext *cx, BytecodeEmitter *bce, unsigned index, uns
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the new offset requires three bytes either by being too big or if
|
||||
* See if the new offset requires four bytes either by being too big or if
|
||||
* the offset has already been inflated (in which case, we need to stay big
|
||||
* to not break the srcnote encoding if this isn't the last srcnote).
|
||||
*/
|
||||
if (offset > (ptrdiff_t)SN_4BYTE_OFFSET_MASK || (*sn & SN_4BYTE_OFFSET_FLAG)) {
|
||||
/* Maybe this offset was already set to a three-byte value. */
|
||||
/* Maybe this offset was already set to a four-byte value. */
|
||||
if (!(*sn & SN_4BYTE_OFFSET_FLAG)) {
|
||||
/* Insert two dummy bytes that will be overwritten shortly. */
|
||||
/* Insert three dummy bytes that will be overwritten shortly. */
|
||||
jssrcnote dummy = 0;
|
||||
if (!(sn = notes.insert(sn, dummy)) ||
|
||||
!(sn = notes.insert(sn, dummy)) ||
|
||||
|
@ -61,7 +61,7 @@ namespace js {
|
||||
M(SRC_ASSIGNOP, "assignop", 0) /* += or another assign-op follows. */ \
|
||||
M(SRC_TRY, "try", 1) /* JSOP_TRY, offset points to goto at the end of the \
|
||||
try block. */ \
|
||||
/* All notes below here are "gettable". See SN_IS_GETTABLE below. */ \
|
||||
/* All notes above here are "gettable". See SN_IS_GETTABLE below. */ \
|
||||
M(SRC_COLSPAN, "colspan", 1) /* Number of columns this opcode spans. */ \
|
||||
M(SRC_NEWLINE, "newline", 0) /* Bytecode follows a source newline. */ \
|
||||
M(SRC_SETLINE, "setline", 1) /* A file-absolute source line number note. */ \
|
||||
@ -136,20 +136,52 @@ SN_IS_TERMINATOR(jssrcnote *sn)
|
||||
#define SN_4BYTE_OFFSET_FLAG 0x80
|
||||
#define SN_4BYTE_OFFSET_MASK 0x7f
|
||||
|
||||
/*
|
||||
* Negative SRC_COLSPAN offsets are rare, but can arise with for(;;) loops and
|
||||
* other constructs that generate code in non-source order. They can also arise
|
||||
* due to failure to update pn->pn_pos.end to be the last child's end -- such
|
||||
* failures are bugs to fix.
|
||||
*
|
||||
* Source note offsets in general must be non-negative and less than 0x800000,
|
||||
* per the above SN_4BYTE_* definitions. To encode negative colspans, we bias
|
||||
* them by the offset domain size and restrict non-negative colspans to less
|
||||
* than half this domain.
|
||||
*/
|
||||
#define SN_COLSPAN_DOMAIN ptrdiff_t(1 << 23)
|
||||
#define SN_OFFSET_BITS 31
|
||||
#define SN_MAX_OFFSET (((size_t) 1 << SN_OFFSET_BITS) - 1)
|
||||
|
||||
#define SN_MAX_OFFSET ((size_t)((ptrdiff_t)SN_4BYTE_OFFSET_FLAG << 24) - 1)
|
||||
inline bool
|
||||
SN_REPRESENTABLE_OFFSET(ptrdiff_t offset)
|
||||
{
|
||||
return 0 <= offset && size_t(offset) <= SN_MAX_OFFSET;
|
||||
}
|
||||
|
||||
/*
|
||||
* SRC_COLSPAN values represent changes to the column number. Colspans are
|
||||
* signed: negative changes arise in describing constructs like for(;;) loops,
|
||||
* that generate code in non-source order. (Negative colspans also have a
|
||||
* history of indicating bugs in updating ParseNodes' source locations.)
|
||||
*
|
||||
* We store colspans using the same variable-length encoding as offsets,
|
||||
* described above. However, unlike offsets, colspans are signed, so we truncate
|
||||
* colspans (SN_COLSPAN_TO_OFFSET) for storage as offsets, and sign-extend
|
||||
* offsets into colspans when we read them (SN_OFFSET_TO_COLSPAN).
|
||||
*/
|
||||
#define SN_COLSPAN_SIGN_BIT (1 << (SN_OFFSET_BITS - 1))
|
||||
#define SN_MIN_COLSPAN (-SN_COLSPAN_SIGN_BIT)
|
||||
#define SN_MAX_COLSPAN (SN_COLSPAN_SIGN_BIT - 1)
|
||||
|
||||
inline bool
|
||||
SN_REPRESENTABLE_COLSPAN(ptrdiff_t colspan)
|
||||
{
|
||||
return SN_MIN_COLSPAN <= colspan && colspan <= SN_MAX_COLSPAN;
|
||||
}
|
||||
|
||||
inline ptrdiff_t
|
||||
SN_OFFSET_TO_COLSPAN(ptrdiff_t offset) {
|
||||
// There should be no bits set outside the field we're going to sign-extend.
|
||||
MOZ_ASSERT(!(offset & ~((1U << SN_OFFSET_BITS) - 1)));
|
||||
// Sign-extend the least significant SN_OFFSET_BITS bits.
|
||||
return (offset ^ SN_COLSPAN_SIGN_BIT) - SN_COLSPAN_SIGN_BIT;
|
||||
}
|
||||
|
||||
inline ptrdiff_t
|
||||
SN_COLSPAN_TO_OFFSET(ptrdiff_t colspan) {
|
||||
// Truncate the two's complement colspan, for storage as an offset.
|
||||
ptrdiff_t offset = colspan & ((1U << SN_OFFSET_BITS) - 1);
|
||||
// When we read this back, we'd better get the value we stored.
|
||||
MOZ_ASSERT(SN_OFFSET_TO_COLSPAN(offset) == colspan);
|
||||
return offset;
|
||||
}
|
||||
|
||||
#define SN_LENGTH(sn) ((js_SrcNoteSpec[SN_TYPE(sn)].arity == 0) ? 1 \
|
||||
: js_SrcNoteLength(sn))
|
||||
|
@ -28,11 +28,9 @@ if (helperThreadCount() > 0) {
|
||||
// Check handling of columns near the limit of our ability to represent them.
|
||||
// (This is hardly thorough, but since web content can't set column numbers,
|
||||
// it's probably not worth it to be thorough.)
|
||||
const maxColumn = Math.pow(2, 22) - 1;
|
||||
const maxColumn = Math.pow(2, 30) - 1;
|
||||
assertEq(evaluate("saveStack().column", { columnNumber: maxColumn }),
|
||||
maxColumn);
|
||||
assertEq(evaluate("saveStack().column", { columnNumber: maxColumn + 1 }),
|
||||
0);
|
||||
|
||||
// Check the 'silently zero' behavior when we reach the limit of the srcnotes
|
||||
// column encoding.
|
||||
|
@ -2848,10 +2848,7 @@ js::PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbyt
|
||||
break;
|
||||
|
||||
if (type == SRC_COLSPAN) {
|
||||
ptrdiff_t colspan = js_GetSrcNoteOffset(sn, 0);
|
||||
|
||||
if (colspan >= SN_COLSPAN_DOMAIN / 2)
|
||||
colspan -= SN_COLSPAN_DOMAIN;
|
||||
ptrdiff_t colspan = SN_OFFSET_TO_COLSPAN(js_GetSrcNoteOffset(sn, 0));
|
||||
MOZ_ASSERT(ptrdiff_t(column) + colspan >= 0);
|
||||
column += colspan;
|
||||
}
|
||||
|
@ -1901,9 +1901,7 @@ SrcNotes(JSContext *cx, HandleScript script, Sprinter *sp)
|
||||
break;
|
||||
|
||||
case SRC_COLSPAN:
|
||||
colspan = js_GetSrcNoteOffset(sn, 0);
|
||||
if (colspan >= SN_COLSPAN_DOMAIN / 2)
|
||||
colspan -= SN_COLSPAN_DOMAIN;
|
||||
colspan = SN_OFFSET_TO_COLSPAN(js_GetSrcNoteOffset(sn, 0));
|
||||
Sprint(sp, "%d", colspan);
|
||||
break;
|
||||
|
||||
|
@ -3598,10 +3598,7 @@ class BytecodeRangeWithPosition : private BytecodeRange
|
||||
while (!SN_IS_TERMINATOR(sn) && snpc <= frontPC()) {
|
||||
SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
|
||||
if (type == SRC_COLSPAN) {
|
||||
ptrdiff_t colspan = js_GetSrcNoteOffset(sn, 0);
|
||||
|
||||
if (colspan >= SN_COLSPAN_DOMAIN / 2)
|
||||
colspan -= SN_COLSPAN_DOMAIN;
|
||||
ptrdiff_t colspan = SN_OFFSET_TO_COLSPAN(js_GetSrcNoteOffset(sn, 0));
|
||||
MOZ_ASSERT(ptrdiff_t(column) + colspan >= 0);
|
||||
column += colspan;
|
||||
} if (type == SRC_SETLINE) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user