denizzzka / dpq2

@@ -150,10 +150,10 @@
Loading
150 150
{
151 151
    const ConvExceptionType type; /// Exception type
152 152
153 -
    this(ConvExceptionType t, string msg, string file = __FILE__, size_t line = __LINE__) pure @safe
153 +
    this(ConvExceptionType t, string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) pure @safe
154 154
    {
155 155
        type = t;
156 -
        super(msg, file, line);
156 +
        super(msg, file, line, next);
157 157
    }
158 158
}
159 159

@@ -18,14 +18,6 @@
Loading
18 18
import std.bitmanip: bigEndianToNative;
19 19
import std.conv: to;
20 20
21 -
version(D_NoBoundsChecks)
22 -
{
23 -
    static assert(false,
24 -
            `It is found what current version of dpq2 is not checks byte arrays bounds properly. `~
25 -
            `To avoid security risks please do not disable built-in bounds check.`
26 -
        );
27 -
}
28 -
29 21
/// Result table's cell coordinates
30 22
private struct Coords
31 23
{
@@ -448,6 +440,48 @@
Loading
448 440
    ubyte[4] lbound; // unknown
449 441
}
450 442
443 +
private @safe struct BytesReader(A = const ubyte[])
444 +
{
445 +
    A arr;
446 +
    size_t currIdx;
447 +
448 +
    this(A a)
449 +
    {
450 +
        arr = a;
451 +
    }
452 +
453 +
    T* read(T)() @trusted
454 +
    {
455 +
        const incremented = currIdx + T.sizeof;
456 +
457 +
        // Malformed buffer?
458 +
        if(incremented > arr.length)
459 +
            throw new AnswerException(ExceptionType.FATAL_ERROR, null);
460 +
461 +
        auto ret = cast(T*) &arr[currIdx];
462 +
463 +
        currIdx = incremented;
464 +
465 +
        return ret;
466 +
    }
467 +
468 +
    A readBuff(size_t len)
469 +
    in(len >= 0)
470 +
    {
471 +
        const incremented = currIdx + len;
472 +
473 +
        // Malformed buffer?
474 +
        if(incremented > arr.length)
475 +
            throw new AnswerException(ExceptionType.FATAL_ERROR, null);
476 +
477 +
        auto ret = arr[currIdx .. incremented];
478 +
479 +
        currIdx = incremented;
480 +
481 +
        return ret;
482 +
    }
483 +
}
484 +
451 485
///
452 486
struct ArrayProperties
453 487
{
@@ -458,14 +492,33 @@
Loading
458 492
459 493
    this(in Value cell)
460 494
    {
461 -
        const ArrayHeader_net* h = cast(ArrayHeader_net*) cell.data.ptr;
495 +
        try
496 +
            fillStruct(cell);
497 +
        catch(AnswerException e)
498 +
        {
499 +
            // Malformed array bytes buffer?
500 +
            if(e.type == ExceptionType.FATAL_ERROR && e.msg is null)
501 +
                throw new ValueConvException(
502 +
                    ConvExceptionType.CORRUPTED_ARRAY,
503 +
                    "Corrupted array",
504 +
                    __FILE__, __LINE__, e
505 +
                );
506 +
            else
507 +
                throw e;
508 +
        }
509 +
    }
510 +
511 +
    private void fillStruct(in Value cell)
512 +
    {
513 +
        auto data = BytesReader!(immutable ubyte[])(cell.data);
514 +
515 +
        const ArrayHeader_net* h = data.read!ArrayHeader_net;
462 516
        int nDims = bigEndianToNative!int(h.ndims);
463 517
        OID = oid2oidType(bigEndianToNative!Oid(h.OID));
464 518
465 519
        if(nDims < 0)
466 -
            throw new AnswerException(ExceptionType.FATAL_ERROR,
520 +
            throw new ValueConvException(ConvExceptionType.CORRUPTED_ARRAY,
467 521
                "Array dimensions number is negative ("~to!string(nDims)~")",
468 -
                __FILE__, __LINE__
469 522
            );
470 523
471 524
        dataOffset = ArrayHeader_net.sizeof + Dim_net.sizeof * nDims;
@@ -481,16 +534,14 @@
Loading
481 534
            const lbound = bigEndianToNative!int(d.lbound);
482 535
483 536
            if(dim_size < 0)
484 -
                throw new AnswerException(ExceptionType.FATAL_ERROR,
537 +
                throw new ValueConvException(ConvExceptionType.CORRUPTED_ARRAY,
485 538
                    "Dimension size is negative ("~to!string(dim_size)~")",
486 -
                    __FILE__, __LINE__
487 539
                );
488 540
489 541
            // FIXME: What is lbound in postgresql array reply?
490 542
            if(!(lbound == 1))
491 -
                throw new AnswerException(ExceptionType.FATAL_ERROR,
543 +
                throw new ValueConvException(ConvExceptionType.CORRUPTED_ARRAY,
492 544
                    "Please report if you came across this error! lbound=="~to!string(lbound),
493 -
                    __FILE__, __LINE__
494 545
                );
495 546
496 547
            dimsSize[i] = dim_size;
@@ -523,36 +574,45 @@
Loading
523 574
        ap = cast(immutable) ArrayProperties(cell);
524 575
525 576
        // Looping through all elements and fill out index of them
577 +
        try
526 578
        {
527 579
            auto elements = new immutable (ubyte)[][ nElems ];
528 580
            auto elementIsNULL = new bool[ nElems ];
529 581
530 -
            size_t curr_offset = ap.dataOffset;
582 +
            auto data = BytesReader!(immutable ubyte[])(cell.data[ap.dataOffset .. $]);
531 583
532 584
            for(uint i = 0; i < nElems; ++i)
533 585
            {
534 -
                ubyte[int.sizeof] size_net; // network byte order
535 -
536 -
                size_net[] = cell.data.safeBufferRead(curr_offset, size_net.sizeof);
586 +
                /// size in network byte order
587 +
                const size_net = data.read!(ubyte[int.sizeof]);
537 588
538 -
                uint size = bigEndianToNative!uint( size_net );
589 +
                uint size = bigEndianToNative!uint(*size_net);
539 590
                if( size == size.max ) // NULL magic number
540 591
                {
541 592
                    elementIsNULL[i] = true;
542 -
                    size = 0;
543 593
                }
544 594
                else
545 595
                {
546 596
                    elementIsNULL[i] = false;
597 +
                    elements[i] = data.readBuff(size);
547 598
                }
548 -
                curr_offset += size_net.sizeof;
549 -
                elements[i] = cell.data.safeBufferRead(curr_offset, size);
550 -
                curr_offset += size;
551 599
            }
552 600
553 601
            this.elements = elements.idup;
554 602
            this.elementIsNULL = elementIsNULL.idup;
555 603
        }
604 +
        catch(AnswerException e)
605 +
        {
606 +
            // Malformed array bytes buffer?
607 +
            if(e.type == ExceptionType.FATAL_ERROR && e.msg is null)
608 +
                throw new ValueConvException(
609 +
                    ConvExceptionType.CORRUPTED_ARRAY,
610 +
                    "Corrupted array",
611 +
                    __FILE__, __LINE__, e
612 +
                );
613 +
            else
614 +
                throw e;
615 +
        }
556 616
    }
557 617
558 618
    /// Returns number of elements in array
@@ -638,16 +698,6 @@
Loading
638 698
    }
639 699
}
640 700
641 -
private auto safeBufferRead(in ubyte[] buff, size_t offset, size_t len)
642 -
{
643 -
    import core.exception: RangeError;
644 -
645 -
    try
646 -
        return buff[ offset .. offset + len ];
647 -
    catch(RangeError e)
648 -
        throw new ValueConvException(ConvExceptionType.CORRUPTED_ARRAY, "Corrupted array");
649 -
}
650 -
651 701
/// Notify
652 702
class Notify
653 703
{
Files Coverage
src/dpq2 91.88%
integration_tests/integration_tests.d 100.00%
Project Totals (19 files) 91.92%
1156.5
TRAVIS_OS_NAME=linux
1155.5
TRAVIS_OS_NAME=linux
1157.5
TRAVIS_OS_NAME=linux

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading