diff --git a/flutter_angle/example/analysis_options.yaml b/flutter_angle/example/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/flutter_angle/example/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/flutter_angle/lib/flutter_angle.dart b/flutter_angle/lib/flutter_angle.dart index ca6ff2f..b25dd36 100755 --- a/flutter_angle/lib/flutter_angle.dart +++ b/flutter_angle/lib/flutter_angle.dart @@ -1,7 +1,6 @@ library flutter_angle; -export 'desktop/index.dart' - if (dart.library.js_interop) 'webgl/index.dart'; +export 'desktop/index.dart' if (dart.library.js_interop) 'webgl/index.dart'; export 'shared/webgl.dart'; export 'shared/options.dart'; -export 'shared/classes.dart'; \ No newline at end of file +export 'shared/classes.dart'; diff --git a/flutter_angle/windows/flutter_angle_plugin.cpp b/flutter_angle/windows/flutter_angle_plugin.cpp index c703f56..2156630 100755 --- a/flutter_angle/windows/flutter_angle_plugin.cpp +++ b/flutter_angle/windows/flutter_angle_plugin.cpp @@ -127,6 +127,22 @@ namespace { return; } + // Input validation to prevent crashes + const int MAX_TEXTURE_SIZE = 8192; + if (width <= 0 || height <= 0) { + result->Error("Invalid texture dimensions", "Width and height must be positive"); + return; + } + if (width > MAX_TEXTURE_SIZE || height > MAX_TEXTURE_SIZE) { + result->Error("Texture too large", "Width and height must be less than " + std::to_string(MAX_TEXTURE_SIZE)); + return; + } + // Check for potential integer overflow + if (width > INT_MAX / height / 4) { + result->Error("Texture too large", "Texture dimensions would cause integer overflow"); + return; + } + std::unique_ptr flutterGLTexture; try{ @@ -147,8 +163,14 @@ namespace { renderers.insert(RendererMap::value_type(textureId, std::move(flutterGLTexture))); renderers[textureId]->createTexture(result); } - catch (OpenGLException ex){ - result->Error(ex.message + ':' + std::to_string(ex.error)); + catch (const OpenGLException& ex){ + result->Error(std::string(ex.message) + ":" + std::to_string(ex.error)); + } + catch (const std::exception& ex) { + result->Error("Standard exception", ex.what()); + } + catch (...) { + result->Error("Unknown exception", "An unknown exception occurred during texture creation"); } } else if (method_call.method_name().compare("updateTexture") == 0 || method_call.method_name().compare("textureFrameAvailable") == 0) { diff --git a/flutter_angle/windows/flutter_gl_texture.cpp b/flutter_angle/windows/flutter_gl_texture.cpp index 4291f60..cbd97ea 100755 --- a/flutter_angle/windows/flutter_gl_texture.cpp +++ b/flutter_angle/windows/flutter_gl_texture.cpp @@ -144,17 +144,67 @@ EGLInfo FlutterGLTexture::initOpenGL(std::unique_ptr>& result) { + // Input validation to prevent buffer overrun + const int MAX_TEXTURE_SIZE = 8192; // Reasonable maximum texture size + if (setWidth <= 0 || setHeight <= 0) { + result->Error("Invalid texture dimensions", "Width and height must be positive"); + return; + } + if (setWidth > MAX_TEXTURE_SIZE || setHeight > MAX_TEXTURE_SIZE) { + result->Error("Texture too large", "Width and height must be less than " + std::to_string(MAX_TEXTURE_SIZE)); + return; + } + + // Check for integer overflow before multiplication + if (setWidth > INT_MAX / setHeight / 4) { + result->Error("Texture too large", "Texture dimensions would cause integer overflow"); + return; + } + if (setWidth == structure.width && setHeight == structure.height && didStart) { return; } if(structure.useBuffer){ + // Update internal dimensions for buffer mode as well + structure.width = setWidth; + structure.height = setHeight; + int64_t size = setWidth * setHeight * 4; - pixels.reset(new uint8_t[size]); + + // Additional safety check + if (size <= 0 || size > SIZE_MAX) { + result->Error("Invalid buffer size", "Calculated buffer size is invalid"); + return; + } + + try { + pixels.reset(new uint8_t[size]); + } catch (const std::bad_alloc&) { + result->Error("Memory allocation failed", "Failed to allocate memory for texture buffer"); + return; + } + + // Validate pixelBuffer is initialized + if (!pixelBuffer) { + result->Error("Pixel buffer not initialized", "Pixel buffer is null"); + return; + } pixelBuffer->buffer = pixels.get(); pixelBuffer->width = setWidth; pixelBuffer->height = setHeight; memset(pixels.get(), 0x00, size); + + // Recreate FBO/RBO to match new size to avoid partial reads/flicker + if (textures.rboId != 0) { + glDeleteRenderbuffers(1, &textures.rboId); + textures.rboId = 0; + } + if (textures.fboId != 0) { + glDeleteFramebuffers(1, &textures.fboId); + textures.fboId = 0; + } + setupOpenGLResources(); if(didStart){ /// we send back the context so that the Dart side can create a linked context. auto response = flutter::EncodableValue(flutter::EncodableMap{ @@ -306,14 +356,14 @@ void FlutterGLTexture::setupOpenGLResources(){ auto error = glGetError(); if (error != GL_NO_ERROR){ std::cerr << "GlError while allocating Renderbuffer" << error << std::endl; - throw new OpenGLException("GlError while allocating Renderbuffer", error); + throw OpenGLException("GlError while allocating Renderbuffer", error); } glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,rbo); auto frameBufferCheck = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (frameBufferCheck != GL_FRAMEBUFFER_COMPLETE){ std::cerr << "Framebuffer error" << frameBufferCheck << std::endl; - throw new OpenGLException("Framebuffer Error while creating Texture", frameBufferCheck); + throw OpenGLException("Framebuffer Error while creating Texture", frameBufferCheck); } error = glGetError(); @@ -329,7 +379,6 @@ void FlutterGLTexture::createTexture(std::unique_ptr(); changeSize(structure.width,structure.height,result); - setupOpenGLResources(); } didStart = true; @@ -349,8 +398,44 @@ void FlutterGLTexture::createTexture(std::unique_ptr>& result){ if(structure.useBuffer){ + // Validate pixelBuffer and its buffer before use + if (!pixelBuffer) { + result->Error("Pixel buffer not initialized", "Pixel buffer is null"); + return; + } + if (!pixelBuffer->buffer) { + result->Error("Pixel buffer data not allocated", "Pixel buffer data is null"); + return; + } + if (pixelBuffer->width <= 0 || pixelBuffer->height <= 0) { + result->Error("Invalid pixel buffer dimensions", "Pixel buffer dimensions are invalid"); + return; + } + + // Check for potential buffer overrun + int64_t requiredSize = pixelBuffer->width * pixelBuffer->height * 4; + if (requiredSize <= 0 || requiredSize > SIZE_MAX) { + result->Error("Invalid buffer size for read operation", "Calculated buffer size is invalid"); + return; + } + glBindFramebuffer(GL_FRAMEBUFFER, textures.fboId); + + // Check for OpenGL errors before read operation + GLenum error = glGetError(); + if (error != GL_NO_ERROR) { + result->Error("OpenGL error before readPixels", "OpenGL error: " + std::to_string(error)); + return; + } + glReadPixels(0, 0, (GLsizei)pixelBuffer->width, (GLsizei)pixelBuffer->height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)pixelBuffer->buffer); + + // Check for OpenGL errors after read operation + error = glGetError(); + if (error != GL_NO_ERROR) { + result->Error("OpenGL error during readPixels", "OpenGL error: " + std::to_string(error)); + return; + } } textureRegistrar->MarkTextureFrameAvailable(textureId); result->Success(); diff --git a/flutter_angle_crash_fix.patch b/flutter_angle_crash_fix.patch new file mode 100644 index 0000000..c9ecc26 Binary files /dev/null and b/flutter_angle_crash_fix.patch differ diff --git a/h_fix.patch b/h_fix.patch new file mode 100644 index 0000000..5da3fba --- /dev/null +++ b/h_fix.patch @@ -0,0 +1,10 @@ +67707ff (HEAD -> main, origin/main, origin/HEAD) updates for pub dev +c113385 Fixed ANGLE spamming issue on debug +c89d398 Fixed binding error +c96e25a added antialias to web +de96ed3 pub dev updates +9570127 Fixed web release bug +b36beeb making web consistent and looking for memory leaks +0654066 updates to fix Linux artifacts +815652a removed glew +b1df2ce update for pub dev