diff --git a/src/CairoContext.cpp b/src/CairoContext.cpp index 1923c6e..326c5f6 100644 --- a/src/CairoContext.cpp +++ b/src/CairoContext.cpp @@ -32,7 +32,8 @@ QoreCairoContext::QoreCairoContext(QoreCairoSurface* surface, ExceptionSink* xsink) : surface_ref(surface) { assert(surface); - surface->ref(); + // NOTE: caller (QPP-generated code via HARD_QORE_VALUE_OBJ_DATA) already holds a reference + // from getReferencedPrivateData(); we take ownership of that reference here cr = cairo_create(surface->getSurface()); checkStatus(xsink); } diff --git a/src/CairoSurface.cpp b/src/CairoSurface.cpp index 6549d9b..b12b230 100644 --- a/src/CairoSurface.cpp +++ b/src/CairoSurface.cpp @@ -37,6 +37,13 @@ QoreCairoSurface::QoreCairoSurface(const std::string& path, double width, double xsink->raiseException("CAIRO-ERROR", "surface dimensions must be positive (%.2f x %.2f)", width, height); return; } + QoreSandboxManagerHelper smh; + if (smh && !smh->checkFilesystemAccess(path.c_str(), QSEC_WRITE | QSEC_CREATE, xsink)) { + return; + } + if (qore_check_io_interrupt(xsink, "SVG surface create")) { + return; + } surface = cairo_svg_surface_create(path.c_str(), width, height); checkStatus(xsink); } @@ -59,6 +66,13 @@ QoreCairoSurface::QoreCairoSurface(const std::string& path, double width, double xsink->raiseException("CAIRO-ERROR", "surface dimensions must be positive (%.2f x %.2f)", width, height); return; } + QoreSandboxManagerHelper smh; + if (smh && !smh->checkFilesystemAccess(path.c_str(), QSEC_WRITE | QSEC_CREATE, xsink)) { + return; + } + if (qore_check_io_interrupt(xsink, "PostScript surface create")) { + return; + } surface = cairo_ps_surface_create(path.c_str(), width, height); checkStatus(xsink); } @@ -87,6 +101,13 @@ QoreCairoSurface::QoreCairoSurface(int width, int height, cairo_format_t format, // Image surface from PNG file QoreCairoSurface::QoreCairoSurface(const std::string& path, ExceptionSink* xsink) : type(CST_IMAGE) { + QoreSandboxManagerHelper smh; + if (smh && !smh->checkFilesystemAccess(path.c_str(), QSEC_READ, xsink)) { + return; + } + if (qore_check_io_interrupt(xsink, "PNG file load")) { + return; + } surface = cairo_image_surface_create_from_png(path.c_str()); cairo_status_t status = cairo_surface_status(surface); if (status != CAIRO_STATUS_SUCCESS) { @@ -172,6 +193,13 @@ void QoreCairoSurface::writeToPng(const std::string& path, ExceptionSink* xsink) xsink->raiseException("CAIRO-ERROR", "writeToPng is only available for image and recording surfaces"); return; } + QoreSandboxManagerHelper smh; + if (smh && !smh->checkFilesystemAccess(path.c_str(), QSEC_WRITE | QSEC_CREATE, xsink)) { + return; + } + if (qore_check_io_interrupt(xsink, "PNG file write")) { + return; + } cairo_status_t status = cairo_surface_write_to_png(surface, path.c_str()); if (status != CAIRO_STATUS_SUCCESS) { xsink->raiseException("CAIRO-ERROR", "failed to write PNG to '%s': %s", diff --git a/src/CairoSvgReader.cpp b/src/CairoSvgReader.cpp index 35a5184..d18d6f3 100644 --- a/src/CairoSvgReader.cpp +++ b/src/CairoSvgReader.cpp @@ -31,6 +31,13 @@ #ifdef HAVE_RSVG QoreCairoSvgReader::QoreCairoSvgReader(const std::string& path, ExceptionSink* xsink) { + QoreSandboxManagerHelper smh; + if (smh && !smh->checkFilesystemAccess(path.c_str(), QSEC_READ, xsink)) { + return; + } + if (qore_check_io_interrupt(xsink, "SVG file load")) { + return; + } GError* error = nullptr; GFile* file = g_file_new_for_path(path.c_str()); handle = rsvg_handle_new_from_gfile_sync(file, RSVG_HANDLE_FLAGS_NONE, nullptr, &error); diff --git a/src/QC_CairoContext.qpp b/src/QC_CairoContext.qpp index 134a6b0..60d2aad 100644 --- a/src/QC_CairoContext.qpp +++ b/src/QC_CairoContext.qpp @@ -214,6 +214,7 @@ nothing CairoContext::setSourceRgba(float r, float g, float b, float a) { @param y Y offset for the surface origin */ nothing CairoContext::setSourceSurface(CairoSurface[QoreCairoSurface] surface, float x, float y) { + ReferenceHolder holder(surface, xsink); ctx->setSourceSurface(surface, x, y, xsink); } @@ -221,6 +222,7 @@ nothing CairoContext::setSourceSurface(CairoSurface[QoreCairoSurface] surface, f /** @param pattern the source pattern */ nothing CairoContext::setSource(CairoPattern[QoreCairoPattern] pattern) { + ReferenceHolder holder(pattern, xsink); ctx->setSource(pattern->getPattern(), xsink); } diff --git a/src/QC_CairoPattern.qpp b/src/QC_CairoPattern.qpp index 6384e09..389826a 100644 --- a/src/QC_CairoPattern.qpp +++ b/src/QC_CairoPattern.qpp @@ -37,6 +37,13 @@ */ qclass CairoPattern [arg=QoreCairoPattern* pattern; ns=Qore::Cairo]; +//! Private constructor - use static factory methods instead +/** @throw CAIRO-ERROR always; CairoPattern objects must be created using static factory methods +*/ +private CairoPattern::constructor() { + xsink->raiseException("CAIRO-ERROR", "CairoPattern cannot be constructed directly; use static factory methods"); +} + //! Creates a linear gradient pattern /** @param x0 start point X @param y0 start point Y @@ -102,6 +109,7 @@ static CairoPattern CairoPattern::createRgba(float r, float g, float b, float a) /** @param surface the source surface */ static CairoPattern CairoPattern::createForSurface(CairoSurface[QoreCairoSurface] surface) { + ReferenceHolder surface_holder(surface, xsink); ReferenceHolder holder(new QoreCairoPattern(surface, xsink), xsink); if (*xsink) { return QoreValue(); diff --git a/src/QC_CairoSurface.qpp b/src/QC_CairoSurface.qpp index 97e93d2..0be28c9 100644 --- a/src/QC_CairoSurface.qpp +++ b/src/QC_CairoSurface.qpp @@ -117,6 +117,13 @@ hashdecl Qore::Cairo::CairoTextExtents { */ qclass CairoSurface [arg=QoreCairoSurface* surface; ns=Qore::Cairo]; +//! Private constructor - use static factory methods instead +/** @throw CAIRO-ERROR always; CairoSurface objects must be created using static factory methods +*/ +private CairoSurface::constructor() { + xsink->raiseException("CAIRO-ERROR", "CairoSurface cannot be constructed directly; use static factory methods"); +} + //! Creates an SVG surface writing to a file /** @param path output file path @param width surface width in points diff --git a/src/QC_CairoSvgReader.qpp b/src/QC_CairoSvgReader.qpp index 0f02de2..12f6d40 100644 --- a/src/QC_CairoSvgReader.qpp +++ b/src/QC_CairoSvgReader.qpp @@ -95,6 +95,7 @@ hash CairoSvgReader::getDimensions() { /** @param ctx the target drawing context */ nothing CairoSvgReader::renderTo(CairoContext[QoreCairoContext] ctx) { + ReferenceHolder holder(ctx, xsink); reader->renderTo(ctx, xsink); } diff --git a/src/cairo-module.h b/src/cairo-module.h index 4c55307..dc50cc8 100644 --- a/src/cairo-module.h +++ b/src/cairo-module.h @@ -27,6 +27,7 @@ #define QORE_CAIRO_MODULE_H #include +#include extern const TypedHashDecl* hashdeclCairoSurfaceInfo; extern const TypedHashDecl* hashdeclCairoMatrix;