From 84877b7706733a57230ade0edb66fc99a3b8ce4f Mon Sep 17 00:00:00 2001 From: xingshunxiang Date: Mon, 23 Jun 2025 15:29:46 +0800 Subject: [PATCH] Fix several bugs from fuzzing case Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICHJSW?from=project-issue Description: some crash bugs from fuzzer Reason: 1. in case1, {@@} will invoke the ETSFormattedParse, if the insertNode is empty, it will return BrokenType and Throw logError, BrokenType will cause nullptr segV in EnumCheck, since it have no tsType, so subsitute it with BrokenExpression, it will has typeError as tsType. 2. in case2, some poccessing of boolean had been lost, now add it. // case2 cannot reproduce on 0603, related change were dropped 3. in case3, parser goes into TypedParser and return an unsupported astnode, so override the related function to return the correct astnode 4. in case4, invalid namespace inside blockstatement cannot be transfered to classDefinition, so cause SegV in the later lowering Tests: ninja tests passed tests/tests-u-runner/runner.sh --ets-cts --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --ets-func-tests --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --astchecker --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --ets-runtime --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --parser --no-js --show-progress --build-dir x64.release --processes=all passed Signed-off-by: xingshunxiang --- .../ets/topLevelStmts/globalClassHandler.cpp | 25 ++++++++++++++--- .../ets/topLevelStmts/globalClassHandler.h | 1 + ets2panda/parser/ETSFormattedParser.cpp | 2 +- ets2panda/parser/ETSparser.h | 2 +- ets2panda/parser/ETSparserNamespaces.cpp | 6 ++--- ets2panda/parser/TypedParser.cpp | 7 ++++- ets2panda/parser/TypedParser.h | 1 + .../ast/compiler/ets/binary_operator_neg.ets | 21 +++++++++++++++ .../compiler/ets/classproperty_init_neg.ets | 18 +++++++++++++ .../compiler/ets/invalid_namespace_neg.ets | 27 +++++++++++++++++++ .../compiler/ets/invalid_namespace_neg2.ets | 22 +++++++++++++++ 11 files changed, 122 insertions(+), 10 deletions(-) create mode 100644 ets2panda/test/ast/compiler/ets/binary_operator_neg.ets create mode 100644 ets2panda/test/ast/compiler/ets/classproperty_init_neg.ets create mode 100644 ets2panda/test/ast/compiler/ets/invalid_namespace_neg.ets create mode 100644 ets2panda/test/ast/compiler/ets/invalid_namespace_neg2.ets diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp index a914f8ad66..9370597459 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp @@ -189,6 +189,23 @@ ArenaVector GlobalClassHandler::TransformNamespaces(Aren return classDecls; } +void GlobalClassHandler::TransformBrokenNamespace(ir::AstNode *node, parser::Program *program) +{ + node->TransformChildrenRecursively( + // clang-format off + // CC-OFFNXT(G.FMT.14-CPP) project code style + [this, &program](ir::AstNode *child) -> ir::AstNode* { + if (child->IsETSModule() && child->AsETSModule()->IsNamespace()) { + auto res = TransformNamespace(child->AsETSModule(), program); + res->SetParent(child->Parent()); + return res; + } + return child; + }, + // clang-format on + "TransformBrokenNamespace"); +} + ir::ClassDeclaration *GlobalClassHandler::TransformNamespace(ir::ETSModule *ns, parser::Program *program) { ir::ClassDeclaration *const globalDecl = CreateTransformedClass(ns); @@ -312,7 +329,6 @@ void GlobalClassHandler::SetupGlobalClass(const ArenaVector & CollectProgramGlobalClasses(globalProgram, namespaces); auto initializerBlockStmts = FormInitStaticBlockMethodStatements(globalProgram, moduleDependencies, std::move(initializerBlock)); - CollectExportedClasses(globalClass, globalProgram->Ast()->Statements()); // NOTE(vpukhov): stdlib checks are to be removed - do not extend the existing logic @@ -423,11 +439,12 @@ ArenaVector GlobalClassHandler::FormInitMethodStatements(parser FormDependentInitTriggers(statements, moduleDependencies); } for (const auto &[p, ps] : initStatements) { + for (auto st : ps) { + TransformBrokenNamespace(st, p); + st->SetParent(nullptr); + } statements.insert(statements.end(), ps.begin(), ps.end()); } - for (auto st : statements) { - st->SetParent(nullptr); - } return statements; } diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h index ae589327d1..fc726e8dd6 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.h @@ -76,6 +76,7 @@ private: ArenaVector> FormInitStaticBlockMethodStatements( parser::Program *program, const ModuleDependencies *moduleDependencies, ArenaVector &&initStatements); + void TransformBrokenNamespace(ir::AstNode *node, parser::Program *program); ArenaVector FormInitMethodStatements(parser::Program *program, const ModuleDependencies *moduleDependencies, diff --git a/ets2panda/parser/ETSFormattedParser.cpp b/ets2panda/parser/ETSFormattedParser.cpp index 93fac4b3e5..4be9f1d50c 100644 --- a/ets2panda/parser/ETSFormattedParser.cpp +++ b/ets2panda/parser/ETSFormattedParser.cpp @@ -71,7 +71,7 @@ ir::Expression *ETSParser::ParseExpressionFormatPlaceholder() LogUnexpectedToken(lexer::TokenType::PUNCTUATOR_FORMAT); const auto &rangeToken = Lexer()->GetToken().Loc(); Lexer()->NextToken(); - return AllocBrokenType(rangeToken); + return AllocBrokenExpression(rangeToken); } ParserImpl::NodeFormatType nodeFormat = GetFormatPlaceholderType(); diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index 6c905bafe6..f038afa6f2 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -390,7 +390,7 @@ private: ir::ModifierFlags flags = ir::ModifierFlags::NONE) override; bool CheckInNamespaceContextIsExported(); ir::ETSModule *ParseNamespaceStatement(ir::ModifierFlags memberModifiers); - ir::ETSModule *ParseNamespace(ir::ModifierFlags flags); + ir::Statement *ParseNamespace(ir::ModifierFlags flags) override; ir::ETSModule *ParseNamespaceImp(ir::ModifierFlags flags); using NamespaceBody = std::tuple, lexer::SourceRange>; NamespaceBody ParseNamespaceBody(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags); diff --git a/ets2panda/parser/ETSparserNamespaces.cpp b/ets2panda/parser/ETSparserNamespaces.cpp index ea4a8feb4b..53e582726f 100644 --- a/ets2panda/parser/ETSparserNamespaces.cpp +++ b/ets2panda/parser/ETSparserNamespaces.cpp @@ -41,7 +41,7 @@ ir::ETSModule *ETSParser::ParseNamespaceStatement(ir::ModifierFlags memberModifi GetContext().Status() |= ParserStatus::IN_NAMESPACE; IncrementNamespaceNestedRank(); - ir::ETSModule *result = ParseNamespace(modifiers); + auto *result = ParseNamespace(modifiers); DecrementNamespaceNestedRank(); if (GetNamespaceNestedRank() == 0) { @@ -50,10 +50,10 @@ ir::ETSModule *ETSParser::ParseNamespaceStatement(ir::ModifierFlags memberModifi if ((memberModifiers & ir::ModifierFlags::DECLARE) != 0) { GetContext().Status() &= ~ParserStatus::IN_AMBIENT_CONTEXT; } - return result; + return result->AsETSModule(); } -ir::ETSModule *ETSParser::ParseNamespace(ir::ModifierFlags flags) +ir::Statement *ETSParser::ParseNamespace(ir::ModifierFlags flags) { if ((GetContext().Status() & ParserStatus::IN_NAMESPACE) == 0) { LogError(diagnostic::NAMESPACE_ONLY_TOP_OR_IN_NAMESPACE); diff --git a/ets2panda/parser/TypedParser.cpp b/ets2panda/parser/TypedParser.cpp index 8e8d168f73..85634a4e63 100644 --- a/ets2panda/parser/TypedParser.cpp +++ b/ets2panda/parser/TypedParser.cpp @@ -166,7 +166,7 @@ ir::Statement *TypedParser::ParsePotentialExpressionStatement(StatementParsingFl } case lexer::TokenType::KEYW_NAMESPACE: { if (((GetContext().Status() & ParserStatus::IN_AMBIENT_CONTEXT) != 0U) || IsNamespaceDecl()) { - return ParseModuleDeclaration(); + return ParseNamespace(ir::ModifierFlags::NONE); } [[fallthrough]]; } @@ -221,6 +221,11 @@ ir::Statement *TypedParser::ParseModuleDeclaration([[maybe_unused]] StatementPar return ParseModuleOrNamespaceDeclaration(startLoc); } +ir::Statement *TypedParser::ParseNamespace([[maybe_unused]] ir::ModifierFlags flags) +{ + return ParseModuleDeclaration(); +} + ir::ArrowFunctionExpression *TypedParser::ParseGenericArrowFunction() { ArrowFunctionContext arrowFunctionContext(this, false); diff --git a/ets2panda/parser/TypedParser.h b/ets2panda/parser/TypedParser.h index 8101ab7123..bb1379b9e5 100644 --- a/ets2panda/parser/TypedParser.h +++ b/ets2panda/parser/TypedParser.h @@ -87,6 +87,7 @@ protected: // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParseModuleDeclaration(StatementParsingFlags flags = StatementParsingFlags::NONE) override; + virtual ir::Statement *ParseNamespace(ir::ModifierFlags flags); virtual void CheckIfTypeParameterNameIsReserved() {}; virtual ArenaVector ParseInterfaceExtendsClause(); virtual ir::Statement *ParseDeclareAndDecorators(StatementParsingFlags flags); diff --git a/ets2panda/test/ast/compiler/ets/binary_operator_neg.ets b/ets2panda/test/ast/compiler/ets/binary_operator_neg.ets new file mode 100644 index 0000000000..8b71c849f8 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/binary_operator_neg.ets @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* @@ label1 */@@/@ + +/* @@@ label1 Error SyntaxError: Unexpected token '@@'. */ +/* @@? 21:93 Error SyntaxError: Identifier expected, got 'end of stream'. */ +/* @@? 21:93 Error SyntaxError: Unexpected token 'end of stream'. */ +/* @@? 21:93 Error SyntaxError: Annotations are not allowed on this type of declaration. */ \ No newline at end of file diff --git a/ets2panda/test/ast/compiler/ets/classproperty_init_neg.ets b/ets2panda/test/ast/compiler/ets/classproperty_init_neg.ets new file mode 100644 index 0000000000..65fa3f5ea6 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/classproperty_init_neg.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class A {b5 : boolean = /* @@ label1 */7;} + +/* @@@ label1 Error TypeError: Type 'int' cannot be assigned to type 'boolean' */ \ No newline at end of file diff --git a/ets2panda/test/ast/compiler/ets/invalid_namespace_neg.ets b/ets2panda/test/ast/compiler/ets/invalid_namespace_neg.ets new file mode 100644 index 0000000000..2f3707f2ac --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/invalid_namespace_neg.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace C{ + { + let y: number = + /* @@ label1 */} + + namespace C { + let xsx = 1 + } +} + +/* @@@ label1 Error SyntaxError: Unexpected token '}'. */ +/* @@? 28:1 Error SyntaxError: Unexpected token. */ diff --git a/ets2panda/test/ast/compiler/ets/invalid_namespace_neg2.ets b/ets2panda/test/ast/compiler/ets/invalid_namespace_neg2.ets new file mode 100644 index 0000000000..c7941e4248 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/invalid_namespace_neg2.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + /* @@ label1 */namespace C { + let my:number = 1 + } +} + +/* @@@ label1 Error SyntaxError: Namespace is allowed only at the top level or inside a namespace. */ -- Gitee