Skip to content

WI #2306 Protect against NullReferenceException when reading NameLiteral property #2801

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--- Diagnostics ---
Line 10[34,40] <27, Error, Syntax> - Syntax error : mismatched input ':zoneA:' expecting user defined word RuleStack=codeElement>dataDescriptionEntry>redefinesClause>dataNameReference, OffendingSymbol=[34,40::zoneA:]<PartialCobolWord>
Line 10[8,41] <30, Error, Semantics> - Semantic error: Illegal REDEFINES: Target cannot be identified

--- Program ---
PROGRAM: TCOBCOMP common:False initial:False recursive:False
author: ? written: ? compiled: ? installation: ? security: ?
--- Intrinsic:Namespace:Program:Global:Local
-- DATA --------
zone1:Alphanumeric
zone1-redef:Alphanumeric
z-label:Alphanumeric
z-content:Alphanumeric
--- Intrinsic
-- TYPES -------
BOOL:BOOL
DATE:DATE
CURRENCY:CURRENCY
STRING:STRING
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
 IDENTIFICATION DIVISION.
PROGRAM-ID. TCOBCOMP.
DATA DIVISION.
WORKING-STORAGE SECTION.
REPLACE ==:zone:== BY ==zone1==.
01 :zone: PIC X(120).
* Undefined REDEFINES target, we get 2 diagnostics:
* - one for the invalid parsing of the Redefines entry
* - one for the invalid semantics of the REDEFINES
01 :zone:-redef REDEFINES :zoneA:.
05 z-label PIC X(20).
05 z-content PIC X(100).
PROCEDURE DIVISION.
GOBACK
.
END PROGRAM TCOBCOMP.
12 changes: 4 additions & 8 deletions TypeCobol/Compiler/CodeElements/Expressions/StorageArea.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using JetBrains.Annotations;
using JetBrains.Annotations;
using TypeCobol.Compiler.Nodes;
using TypeCobol.Compiler.Scanner;

Expand Down Expand Up @@ -536,7 +532,7 @@ public IntrinsicFunctionCall([CanBeNull] ExternalName intrinsicFunctionName, Cal
[CanBeNull]
public ExternalName IntrinsicFunctionName { get; private set; }
public override string FunctionName { get { return IntrinsicFunctionName?.Name; } }
public override Token FunctionNameToken { get { return IntrinsicFunctionName?.NameLiteral.Token; } }
public override Token FunctionNameToken { get { return IntrinsicFunctionName?.NameLiteral?.Token; } }

public override bool NeedDeclaration
{
Expand Down Expand Up @@ -567,7 +563,7 @@ public UserDefinedFunctionCall([CanBeNull] SymbolReference functionName, CallSit
[CanBeNull]
public SymbolReference UserDefinedFunctionName { get; private set; }
public override string FunctionName { get { return UserDefinedFunctionName?.Name; } }
public override Token FunctionNameToken { get { return UserDefinedFunctionName?.NameLiteral.Token; } }
public override Token FunctionNameToken { get { return UserDefinedFunctionName?.NameLiteral?.Token; } }

public override string Namespace { get { return (UserDefinedFunctionName as QualifiedSymbolReference) == null ? null : ((QualifiedSymbolReference)UserDefinedFunctionName).Tail.Name; } }

Expand All @@ -592,7 +588,7 @@ public ProcedureCall(SymbolReference name, List<CallSiteParameter> inputs, List<

public SymbolReference ProcedureName { get; private set; }
public override string FunctionName { get { return ProcedureName.Name; } }
public override Token FunctionNameToken { get { return ProcedureName.NameLiteral.Token; } }
public override Token FunctionNameToken { get { return ProcedureName.NameLiteral?.Token; } }

public List<CallSiteParameter> InputParameters { get; private set; }
public List<CallSiteParameter> InoutParameters { get; private set; }
Expand Down
4 changes: 2 additions & 2 deletions TypeCobol/Compiler/CodeModel/SymbolTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ public IList<Paragraph> GetParagraph(SymbolReference symbolRef, Section sectionN
{
//If paragraph is qualified we get a paragraph and a section name
var qualifiedSymbolReference = (QualifiedSymbolReference) symbolRef;
paragraphName = qualifiedSymbolReference.NameLiteral.Value;
paragraphName = qualifiedSymbolReference.Head.Name;
parentSectionName = qualifiedSymbolReference.Tail.Name;
}
else
Expand All @@ -830,7 +830,7 @@ public IList<Paragraph> GetParagraph(SymbolReference symbolRef, Section sectionN
}

//Retrieve all paragraphs with matching name, then apply additional filters
if (Paragraphs.TryGetValue(paragraphName, out var candidates))
if (paragraphName != null && Paragraphs.TryGetValue(paragraphName, out var candidates))
{
if (parentSectionName != null)
{
Expand Down
9 changes: 4 additions & 5 deletions TypeCobol/Compiler/Diagnostics/Cobol2002Checker.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
using System.Linq;
using System.Collections.Generic;
using TypeCobol.Compiler.AntlrUtils;
using TypeCobol.Compiler.AntlrUtils;
using TypeCobol.Compiler.CodeElements;
using TypeCobol.Compiler.CodeElements.Expressions;
using TypeCobol.Compiler.Parser;
using TypeCobol.Compiler.Parser.Generated;
using TypeCobol.Compiler.Nodes;
using TypeCobol.Compiler.Scanner;

namespace TypeCobol.Compiler.Diagnostics
{
Expand Down Expand Up @@ -147,7 +144,9 @@ public static void OnNode(DataRedefines redefinesNode)

if (redefinedVariable == null)
{
string message = "Illegal REDEFINES: Symbol \'" + redefinesSymbolReference + "\' is not referenced";
var message = redefinesSymbolReference.Name != null
? "Illegal REDEFINES: Symbol \'" + redefinesSymbolReference + "\' is not referenced"
: "Illegal REDEFINES: Target cannot be identified";
DiagnosticUtils.AddError(redefinesNode, message, redefinesSymbolReference, code: MessageCode.SemanticTCErrorInParser);
return;
}
Expand Down
10 changes: 8 additions & 2 deletions TypeCobol/Compiler/Diagnostics/CodeElementCheckers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ private static void CheckCallUsings(CallStatement statement)
{
foreach (var inputParameter in statement.InputParameters)
{
var errorPosition = inputParameter.StorageAreaOrValue?.MainSymbolReference?.NameLiteral.Token;
var errorPosition = inputParameter.StorageAreaOrValue?.MainSymbolReference?.NameLiteral?.Token;

// TODO#249 these checks should be done during semantic phase, after symbol type resolution
// TODO#249 if input is a file name AND input.SendingMode.Value == SendingMode.ByContent OR ByValue
Expand Down Expand Up @@ -736,10 +736,16 @@ public static void OnCodeElement(RepositoryParagraph paragraph, CodeElementsPars
{
foreach (var intrinsicFunction in intrinsicFunctions)
{
Token token = intrinsicFunction.NameLiteral.Token;
var intrinsicFunctionName = intrinsicFunction.Name;
if (!CobolIntrinsicFunctions.IsAllowedInRepositoryParagraph(intrinsicFunctionName))
{
/*
* NameLiteral cannot be null here, otherwise intrinsicFuntionName would also be null
* and IsAllowedInRepositoryParagraph would then have returned true.
*/
System.Diagnostics.Debug.Assert(intrinsicFunction.NameLiteral != null);

Token token = intrinsicFunction.NameLiteral.Token;
DiagnosticUtils.AddError(paragraph, $"\"{intrinsicFunctionName}\" was specified in the \"FUNCTION\" phrase of the \"REPOSITORY\" paragraph, but the keyword \"FUNCTION\" is always required for this function.", token);
}
}
Expand Down
3 changes: 1 addition & 2 deletions TypeCobol/Compiler/Diagnostics/TypeCobolChecker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -618,10 +618,9 @@ public static void OnNode(FunctionDeclaration functionDeclaration)
var functions = functionDeclaration.SymbolTable.GetFunction(headerNameURI, functionDeclaration.Profile);
if (functions.Count > 1)
{
Token nameToken = header.FunctionName.NameLiteral.Token;
DiagnosticUtils.AddError(functionDeclaration,
"A function \"" + headerNameURI.Head + "\" with the same profile already exists in namespace \"" +
headerNameURI.Tail + "\".", nameToken, null, MessageCode.SemanticTCErrorInParser);
headerNameURI.Tail + "\".", header.FunctionName, MessageCode.SemanticTCErrorInParser);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using TypeCobol.Compiler.AntlrUtils;
using TypeCobol.Compiler.CodeElements;
using TypeCobol.Compiler.Parser.Generated;
using System.Collections.Generic;
using TypeCobol.Compiler.Diagnostics;
using TypeCobol.Compiler.Scanner;

Expand Down Expand Up @@ -240,13 +239,21 @@ internal StorageArea CreateLinageCounterSpecialRegister(CodeElementsParser.Linag
var specialRegister = new FilePropertySpecialRegister(
ParseTreeUtils.GetFirstToken(context.LINAGE_COUNTER()),
CobolWordsBuilder.CreateFileNameReference(context.fileNameReference()));
if(specialRegister.DataDescriptionEntry != null) {
var dataDescription = specialRegister.DataDescriptionEntry;
CobolWordsBuilder.symbolInformationForTokens[specialRegister.DataDescriptionEntry.DataName.NameLiteral.Token] = specialRegister.DataDescriptionEntry.DataName;

var dataName = specialRegister.DataDescriptionEntry?.DataName;
var dataNameToken = dataName?.NameLiteral?.Token;
if (dataNameToken != null)
{
CobolWordsBuilder.symbolInformationForTokens[dataNameToken] = dataName;
}
if (specialRegister.SymbolReference != null) {
CobolWordsBuilder.symbolInformationForTokens[specialRegister.SymbolReference.NameLiteral.Token] = specialRegister.SymbolReference;

var specialRegisterReference = specialRegister.SymbolReference;
var specialRegisterReferenceToken = specialRegisterReference?.NameLiteral?.Token;
if (specialRegisterReferenceToken != null)
{
CobolWordsBuilder.symbolInformationForTokens[specialRegisterReferenceToken] = specialRegisterReference;
}
Comment on lines +243 to 255
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is repeated 3 times.
It could be factorized in a methode AddToSymbolInformation with this code:

        private void AddToSymbolInformation(SymbolDefinition specialRegisterName, SymbolReference specialRegisterReference)
        {
            var specialRegisterNameToken = specialRegisterName?.NameLiteral?.Token;
            if (specialRegisterNameToken != null)
            {
                CobolWordsBuilder.symbolInformationForTokens[specialRegisterNameToken] = specialRegisterName;
            }

            var specialRegisterReferenceToken = specialRegisterReference?.NameLiteral?.Token;
            if (specialRegisterReferenceToken != null)
            {
                CobolWordsBuilder.symbolInformationForTokens[specialRegisterReferenceToken] = specialRegisterReference;
            }
        }

Calll it like this;
AddToSymbolInformation(specialRegister.DataDescriptionEntry?.DataName, specialRegister.SymbolReference);


return specialRegister;
}

Expand All @@ -255,14 +262,19 @@ internal StorageArea CreateAddressOfSpecialRegister(CodeElementsParser.AddressOf
var specialRegister = new StorageAreaPropertySpecialRegister(
ParseTreeUtils.GetFirstToken(context.ADDRESS()),
CreateStorageAreaReference(context.storageAreaReference()));
if (specialRegister.DataDescriptionEntry != null)

var specialRegisterName = specialRegister.DataDescriptionEntry?.DataName;
var specialRegisterNameToken = specialRegisterName?.NameLiteral?.Token;
if (specialRegisterNameToken != null)
{
var dataDescription = specialRegister.DataDescriptionEntry;
CobolWordsBuilder.symbolInformationForTokens[specialRegister.DataDescriptionEntry.DataName.NameLiteral.Token] = specialRegister.DataDescriptionEntry.DataName;
CobolWordsBuilder.symbolInformationForTokens[specialRegisterNameToken] = specialRegisterName;
}
if (specialRegister.SymbolReference != null)

var specialRegisterReference = specialRegister.SymbolReference;
var specialRegisterReferenceToken = specialRegisterReference?.NameLiteral?.Token;
if (specialRegisterReferenceToken != null)
{
CobolWordsBuilder.symbolInformationForTokens[specialRegister.SymbolReference.NameLiteral.Token] = specialRegister.SymbolReference;
CobolWordsBuilder.symbolInformationForTokens[specialRegisterReferenceToken] = specialRegisterReference;
}
return specialRegister;
}
Expand All @@ -272,15 +284,21 @@ internal StorageArea CreateLengthOfSpecialRegister(CodeElementsParser.LengthOfSp
var specialRegister = new StorageAreaPropertySpecialRegister(
ParseTreeUtils.GetFirstToken(context.LENGTH()),
CreateStorageAreaReference(context.storageAreaReference()));
if (specialRegister.DataDescriptionEntry != null)

var specialRegisterDataName = specialRegister.DataDescriptionEntry?.DataName;
var specialRegisterDataNameToken = specialRegisterDataName?.NameLiteral?.Token;
if (specialRegisterDataNameToken != null)
{
var dataDescription = specialRegister.DataDescriptionEntry;
CobolWordsBuilder.symbolInformationForTokens[specialRegister.DataDescriptionEntry.DataName.NameLiteral.Token] = specialRegister.DataDescriptionEntry.DataName;
CobolWordsBuilder.symbolInformationForTokens[specialRegisterDataNameToken] = specialRegisterDataName;
}
if (specialRegister.SymbolReference != null)

var specialRegisterReference = specialRegister.SymbolReference;
var specialRegisterReferenceToken = specialRegisterReference?.NameLiteral?.Token;
if (specialRegisterReferenceToken != null)
{
CobolWordsBuilder.symbolInformationForTokens[specialRegister.SymbolReference.NameLiteral.Token] = specialRegister.SymbolReference;
CobolWordsBuilder.symbolInformationForTokens[specialRegisterReferenceToken] = specialRegisterReference;
}

return specialRegister;
}

Expand Down Expand Up @@ -317,8 +335,12 @@ internal StorageArea CreateFunctionIdentifier(CodeElementsParser.FunctionIdentif
if (functionCall.FunctionName != null && functionCall.FunctionNameToken != null)
{
var functionCallResult = new FunctionCallResult(functionCall);
System.Diagnostics.Debug.Assert(functionCallResult.DataDescriptionEntry.DataName != null);
System.Diagnostics.Debug.Assert(functionCallResult.DataDescriptionEntry.DataName.NameLiteral.Token != null);
CobolWordsBuilder.symbolInformationForTokens[functionCallResult.DataDescriptionEntry.DataName.NameLiteral.Token] =
functionCallResult.DataDescriptionEntry.DataName;
System.Diagnostics.Debug.Assert(functionCallResult.SymbolReference != null);
System.Diagnostics.Debug.Assert(functionCallResult.SymbolReference.NameLiteral.Token != null);
CobolWordsBuilder.symbolInformationForTokens[functionCallResult.SymbolReference.NameLiteral.Token] =
functionCallResult.SymbolReference;
return functionCallResult;
Expand Down
47 changes: 40 additions & 7 deletions TypeCobol/Compiler/Parser/CodeElementBuilder/CobolWordsBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ internal CharacterValue CreateFigurativeConstant(CodeElementsParser.FigurativeCo
if (context.symbolicCharacterReference() != null)
{
var symbolicCharacterReference = CreateSymbolicCharacterReference(context.symbolicCharacterReference());
System.Diagnostics.Debug.Assert(symbolicCharacterReference.NameLiteral != null);
System.Diagnostics.Debug.Assert(symbolicCharacterReference.NameLiteral.Token != null);
return new CharacterValue(symbolicCharacterReference);
}

Expand Down Expand Up @@ -172,6 +174,8 @@ private RepeatedCharacterValue CreateRepeatedCharacterValue([CanBeNull] Token al
if (context.symbolicCharacterReference() != null)
{
var symbolicCharacterReference = CreateSymbolicCharacterReference(context.symbolicCharacterReference());
System.Diagnostics.Debug.Assert(symbolicCharacterReference.NameLiteral != null);
System.Diagnostics.Debug.Assert(symbolicCharacterReference.NameLiteral.Token != null);
return new RepeatedCharacterValue(allToken, symbolicCharacterReference);
}

Expand Down Expand Up @@ -803,7 +807,13 @@ internal SymbolReference CreateIndexNameReference(CodeElementsParser.QualifiedIn

var reference = CreateQualifiedSymbolReference(new SymbolReference(headLiteral, SymbolType.IndexName), new SymbolReference(CreateAlphanumericValue(tail[0]), SymbolType.IndexName), false);
for (int c = 1; c < tail.Length; c++) reference = CreateQualifiedSymbolReference(reference, new SymbolReference(CreateAlphanumericValue(tail[c]), SymbolType.IndexName), false);
symbolInformationForTokens[reference.NameLiteral.Token] = reference;

var token = reference.NameLiteral?.Token;
if (token != null)
{
symbolInformationForTokens[token] = reference;
}

Comment on lines +810 to +816
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is repeated 4 times. Similar factorization with method:

        private void AddToSymbolInformation(SymbolReference reference)
        {
            var token = reference.NameLiteral?.Token;
            if (token != null)
            {
                symbolInformationForTokens[token] = reference;
            }
        }

return reference;
}

Expand Down Expand Up @@ -871,7 +881,12 @@ internal SymbolReference CreateQualifiedParagraphNameReference(CodeElementsParse
private SymbolReference CreateQualifiedParagraphNameReference(CodeElementsParser.ParagraphNameReferenceContext head, CodeElementsParser.SectionNameReferenceContext tail, bool isCOBOL = true)
{
var reference = CreateQualifiedSymbolReference(CreateParagraphNameReference(head), CreateSectionNameReference(tail), isCOBOL);
symbolInformationForTokens[reference.NameLiteral.Token] = reference;
var token = reference.NameLiteral?.Token;
if (token != null)
{
symbolInformationForTokens[token] = reference;
}

return reference;
}

Expand Down Expand Up @@ -912,9 +927,11 @@ private SymbolReference CreateQualifiedDataName(CodeElementsParser.DataNameRefer
}
qname = CreateQualifiedSymbolReference(qname, current, isCOBOL);
}
if (qname != null)

var token = qname?.NameLiteral?.Token;
if (token != null)
{
symbolInformationForTokens[qname.NameLiteral.Token] = qname;
symbolInformationForTokens[token] = qname;
return qname;
}

Expand Down Expand Up @@ -954,7 +971,13 @@ private SymbolReference CreateQualifiedConditionName(CodeElementsParser.Conditio
qname = CreateQualifiedSymbolReference(qname, part, isCOBOL);
}
}
symbolInformationForTokens[qname.NameLiteral.Token] = qname;

var token = qname.NameLiteral?.Token;
if (token != null)
{
symbolInformationForTokens[token] = qname;
}

return qname;
}

Expand Down Expand Up @@ -1015,7 +1038,12 @@ private SymbolReference CreateQualifiedDataNameOrQualifiedConditionNameTCFunctio
{
var reference = CreateQualifiedSymbolReference(CreateDataNameReferenceOrConditionNameReferenceOrConditionForUPSISwitchNameReferenceOrTCFunctionProcedure(head), CreateDataNameReferenceOrFileNameReferenceOrMnemonicForUPSISwitchNameReference(tail[0]), isCOBOL);
for (int c = 1; c < tail.Length; c++) reference = CreateQualifiedSymbolReference(reference, CreateDataNameReferenceOrFileNameReferenceOrMnemonicForUPSISwitchNameReference(tail[c]), isCOBOL);
symbolInformationForTokens[reference.NameLiteral.Token] = reference;
var token = reference.NameLiteral?.Token;
if (token != null)
{
symbolInformationForTokens[token] = reference;
}

return reference;
}

Expand Down Expand Up @@ -1134,7 +1162,12 @@ internal ExternalName CreateQualifiedTextName(CodeElementsParser.QualifiedTextNa
{
ExternalName libraryName = CreateLibraryName(context.libraryName());
var qualifiedTextName = new QualifiedTextName(textName, libraryName);
symbolInformationForTokens[qualifiedTextName.NameLiteral.Token] = qualifiedTextName;
var textNameToken = qualifiedTextName.NameLiteral?.Token;
if (textNameToken != null)
{
symbolInformationForTokens[textNameToken] = qualifiedTextName;
}

return qualifiedTextName;
}
}
Expand Down
Loading
Loading