Create PropertyDescriptorImpl under nonCancelableSection

PropertyDescriptorImpl initialization consists of two phases:
ctor + setType.
When PropertyDescriptorImpl is created wrapped descriptor
(e.g. WithDestructuringDeclaration) is leaked through bindingTrace
with not fully initialized `containingDeclaration` (that is
PropertyDescriptorImpl).
If PCE happens after this unsafe publication prior to `setType` then it
will be case with NPE on fully initialized instance reading.

#KT-56388 Fixed
This commit is contained in:
Vladimir Dolzhenko
2023-02-02 17:13:41 +01:00
committed by Space Team
parent e0dce31cde
commit 9be4aa2e02
@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.resolve;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.intellij.openapi.diagnostic.ControlFlowException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import kotlin.Pair; import kotlin.Pair;
@@ -315,81 +317,89 @@ public class DescriptorResolver {
@NotNull Annotations additionalAnnotations, @NotNull Annotations additionalAnnotations,
@Nullable InferenceSession inferenceSession @Nullable InferenceSession inferenceSession
) { ) {
KotlinType varargElementType = null; try {
KotlinType variableType = type; KotlinType varargElementType = null;
if (valueParameter.hasModifier(VARARG_KEYWORD)) { KotlinType variableType = type;
varargElementType = type; if (valueParameter.hasModifier(VARARG_KEYWORD)) {
variableType = getVarargParameterType(type); varargElementType = type;
} variableType = getVarargParameterType(type);
Annotations valueParameterAnnotations = resolveValueParameterAnnotations(scope, valueParameter, trace, additionalAnnotations);
KtDestructuringDeclaration destructuringDeclaration = valueParameter.getDestructuringDeclaration();
Function0<List<VariableDescriptor>> destructuringVariables;
if (destructuringDeclaration != null) {
if (!languageVersionSettings.supportsFeature(LanguageFeature.DestructuringLambdaParameters)) {
trace.report(Errors.UNSUPPORTED_FEATURE.on(valueParameter,
TuplesKt.to(LanguageFeature.DestructuringLambdaParameters, languageVersionSettings)));
} }
destructuringVariables = () -> { Annotations valueParameterAnnotations = resolveValueParameterAnnotations(scope, valueParameter, trace, additionalAnnotations);
ReceiverParameterDescriptor dispatchReceiver = owner.getDispatchReceiverParameter();
assert dispatchReceiver == null || dispatchReceiver.getContainingDeclaration() instanceof ScriptDescriptor
: "Destructuring declarations are only be parsed for lambdas, and they must not have a dispatch receiver";
LexicalScope scopeForDestructuring =
ScopeUtilsKt.createScopeForDestructuring(scope, owner.getExtensionReceiverParameter());
List<VariableDescriptor> result = KtDestructuringDeclaration destructuringDeclaration = valueParameter.getDestructuringDeclaration();
destructuringDeclarationResolver.resolveLocalVariablesFromDestructuringDeclaration(
scope,
destructuringDeclaration, new TransientReceiver(type), /* initializer = */ null,
ExpressionTypingContext.newContext(
trace, scopeForDestructuring, DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE,
languageVersionSettings, dataFlowValueFactory, inferenceSession
)
);
modifiersChecker.withTrace(trace).checkModifiersForDestructuringDeclaration(destructuringDeclaration); Function0<List<VariableDescriptor>> destructuringVariables;
return result; if (destructuringDeclaration != null) {
}; if (!languageVersionSettings.supportsFeature(LanguageFeature.DestructuringLambdaParameters)) {
trace.report(Errors.UNSUPPORTED_FEATURE.on(valueParameter,
TuplesKt.to(LanguageFeature.DestructuringLambdaParameters, languageVersionSettings)));
}
destructuringVariables = () -> {
ReceiverParameterDescriptor dispatchReceiver = owner.getDispatchReceiverParameter();
assert dispatchReceiver == null || dispatchReceiver.getContainingDeclaration() instanceof ScriptDescriptor
: "Destructuring declarations are only be parsed for lambdas, and they must not have a dispatch receiver";
LexicalScope scopeForDestructuring =
ScopeUtilsKt.createScopeForDestructuring(scope, owner.getExtensionReceiverParameter());
List<VariableDescriptor> result =
destructuringDeclarationResolver.resolveLocalVariablesFromDestructuringDeclaration(
scope,
destructuringDeclaration, new TransientReceiver(type), /* initializer = */ null,
ExpressionTypingContext.newContext(
trace, scopeForDestructuring, DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE,
languageVersionSettings, dataFlowValueFactory, inferenceSession
)
);
modifiersChecker.withTrace(trace).checkModifiersForDestructuringDeclaration(destructuringDeclaration);
return result;
};
}
else {
destructuringVariables = null;
}
Name parameterName;
if (destructuringDeclaration == null) {
// NB: val/var for parameter is only allowed in primary constructors where single underscore names are still prohibited.
// The problem with val/var is that when lazy resolve try to find their descriptor, it searches through the member scope
// of containing class where, it can not find a descriptor with special name.
// Thus, to preserve behavior, we don't use a special name for val/var.
parameterName = !valueParameter.hasValOrVar() && UnderscoreUtilKt.isSingleUnderscore(valueParameter)
? Name.special("<anonymous parameter " + index + ">")
: KtPsiUtil.safeName(valueParameter.getName());
}
else {
parameterName = Name.special("<name for destructuring parameter " + index + ">");
}
ValueParameterDescriptorImpl valueParameterDescriptor = ValueParameterDescriptorImpl.createWithDestructuringDeclarations(
owner,
null,
index,
valueParameterAnnotations,
parameterName,
variableType,
valueParameter.hasDefaultValue(),
valueParameter.hasModifier(CROSSINLINE_KEYWORD),
valueParameter.hasModifier(NOINLINE_KEYWORD),
varargElementType,
KotlinSourceElementKt.toSourceElement(valueParameter),
destructuringVariables
);
trace.record(BindingContext.VALUE_PARAMETER, valueParameter, valueParameterDescriptor);
return valueParameterDescriptor;
} }
else { catch (Exception e) {
destructuringVariables = null; if (e instanceof ControlFlowException) {
throw new IllegalStateException("Method should be run under nonCancelableSection", e);
}
throw e;
} }
Name parameterName;
if (destructuringDeclaration == null) {
// NB: val/var for parameter is only allowed in primary constructors where single underscore names are still prohibited.
// The problem with val/var is that when lazy resolve try to find their descriptor, it searches through the member scope
// of containing class where, it can not find a descriptor with special name.
// Thus, to preserve behavior, we don't use a special name for val/var.
parameterName = !valueParameter.hasValOrVar() && UnderscoreUtilKt.isSingleUnderscore(valueParameter)
? Name.special("<anonymous parameter " + index + ">")
: KtPsiUtil.safeName(valueParameter.getName());
}
else {
parameterName = Name.special("<name for destructuring parameter " + index + ">");
}
ValueParameterDescriptorImpl valueParameterDescriptor = ValueParameterDescriptorImpl.createWithDestructuringDeclarations(
owner,
null,
index,
valueParameterAnnotations,
parameterName,
variableType,
valueParameter.hasDefaultValue(),
valueParameter.hasModifier(CROSSINLINE_KEYWORD),
valueParameter.hasModifier(NOINLINE_KEYWORD),
varargElementType,
KotlinSourceElementKt.toSourceElement(valueParameter),
destructuringVariables
);
trace.record(BindingContext.VALUE_PARAMETER, valueParameter, valueParameterDescriptor);
return valueParameterDescriptor;
} }
@NotNull @NotNull
@@ -913,148 +923,150 @@ public class DescriptorResolver {
annotationSplitter.getOtherAnnotations()) annotationSplitter.getOtherAnnotations())
); );
PropertyDescriptorImpl propertyDescriptor = PropertyDescriptorImpl.create( return ProgressManager.getInstance().computeInNonCancelableSection(() -> {
container, PropertyDescriptorImpl propertyDescriptor = PropertyDescriptorImpl.create(
propertyAnnotations, container,
modality, propertyAnnotations,
visibility, modality,
isVar, visibility,
KtPsiUtil.safeName(variableDeclaration.getName()), isVar,
CallableMemberDescriptor.Kind.DECLARATION, KtPsiUtil.safeName(variableDeclaration.getName()),
KotlinSourceElementKt.toSourceElement(variableDeclaration), CallableMemberDescriptor.Kind.DECLARATION,
modifierList != null && modifierList.hasModifier(KtTokens.LATEINIT_KEYWORD), KotlinSourceElementKt.toSourceElement(variableDeclaration),
modifierList != null && modifierList.hasModifier(KtTokens.CONST_KEYWORD), modifierList != null && modifierList.hasModifier(KtTokens.LATEINIT_KEYWORD),
modifierList != null && PsiUtilsKt.hasExpectModifier(modifierList) && container instanceof PackageFragmentDescriptor || modifierList != null && modifierList.hasModifier(KtTokens.CONST_KEYWORD),
container instanceof ClassDescriptor && ((ClassDescriptor) container).isExpect(), modifierList != null && PsiUtilsKt.hasExpectModifier(modifierList) && container instanceof PackageFragmentDescriptor ||
modifierList != null && PsiUtilsKt.hasActualModifier(modifierList), container instanceof ClassDescriptor && ((ClassDescriptor) container).isExpect(),
modifierList != null && modifierList.hasModifier(KtTokens.EXTERNAL_KEYWORD), modifierList != null && PsiUtilsKt.hasActualModifier(modifierList),
propertyInfo.getHasDelegate() modifierList != null && modifierList.hasModifier(KtTokens.EXTERNAL_KEYWORD),
); propertyInfo.getHasDelegate()
);
List<TypeParameterDescriptorImpl> typeParameterDescriptors; List<TypeParameterDescriptorImpl> typeParameterDescriptors;
LexicalScope scopeForDeclarationResolutionWithTypeParameters; LexicalScope scopeForDeclarationResolutionWithTypeParameters;
LexicalScope scopeForInitializerResolutionWithTypeParameters; LexicalScope scopeForInitializerResolutionWithTypeParameters;
KotlinType receiverType = null; KotlinType receiverType = null;
{ {
List<KtTypeParameter> typeParameters = variableDeclaration.getTypeParameters(); List<KtTypeParameter> typeParameters = variableDeclaration.getTypeParameters();
if (typeParameters.isEmpty()) { if (typeParameters.isEmpty()) {
scopeForDeclarationResolutionWithTypeParameters = scopeForDeclarationResolution; scopeForDeclarationResolutionWithTypeParameters = scopeForDeclarationResolution;
scopeForInitializerResolutionWithTypeParameters = scopeForInitializerResolution; scopeForInitializerResolutionWithTypeParameters = scopeForInitializerResolution;
typeParameterDescriptors = Collections.emptyList(); typeParameterDescriptors = Collections.emptyList();
} }
else { else {
LexicalWritableScope writableScopeForDeclarationResolution = new LexicalWritableScope( LexicalWritableScope writableScopeForDeclarationResolution = new LexicalWritableScope(
scopeForDeclarationResolution, container, false, new TraceBasedLocalRedeclarationChecker(trace, overloadChecker), scopeForDeclarationResolution, container, false, new TraceBasedLocalRedeclarationChecker(trace, overloadChecker),
LexicalScopeKind.PROPERTY_HEADER); LexicalScopeKind.PROPERTY_HEADER);
LexicalWritableScope writableScopeForInitializerResolution = new LexicalWritableScope( LexicalWritableScope writableScopeForInitializerResolution = new LexicalWritableScope(
scopeForInitializerResolution, container, false, LocalRedeclarationChecker.DO_NOTHING.INSTANCE, scopeForInitializerResolution, container, false, LocalRedeclarationChecker.DO_NOTHING.INSTANCE,
LexicalScopeKind.PROPERTY_HEADER); LexicalScopeKind.PROPERTY_HEADER);
typeParameterDescriptors = resolveTypeParametersForDescriptor( typeParameterDescriptors = resolveTypeParametersForDescriptor(
propertyDescriptor, propertyDescriptor,
scopeForDeclarationResolution, typeParameters, trace); scopeForDeclarationResolution, typeParameters, trace);
for (TypeParameterDescriptor descriptor : typeParameterDescriptors) { for (TypeParameterDescriptor descriptor : typeParameterDescriptors) {
writableScopeForDeclarationResolution.addClassifierDescriptor(descriptor); writableScopeForDeclarationResolution.addClassifierDescriptor(descriptor);
writableScopeForInitializerResolution.addClassifierDescriptor(descriptor); writableScopeForInitializerResolution.addClassifierDescriptor(descriptor);
}
writableScopeForDeclarationResolution.freeze();
writableScopeForInitializerResolution.freeze();
resolveGenericBounds(variableDeclaration, propertyDescriptor, writableScopeForDeclarationResolution, typeParameterDescriptors, trace);
scopeForDeclarationResolutionWithTypeParameters = writableScopeForDeclarationResolution;
scopeForInitializerResolutionWithTypeParameters = writableScopeForInitializerResolution;
} }
writableScopeForDeclarationResolution.freeze();
writableScopeForInitializerResolution.freeze();
resolveGenericBounds(variableDeclaration, propertyDescriptor, writableScopeForDeclarationResolution, typeParameterDescriptors, trace);
scopeForDeclarationResolutionWithTypeParameters = writableScopeForDeclarationResolution;
scopeForInitializerResolutionWithTypeParameters = writableScopeForInitializerResolution;
} }
}
KtTypeReference receiverTypeRef = variableDeclaration.getReceiverTypeReference(); KtTypeReference receiverTypeRef = variableDeclaration.getReceiverTypeReference();
ReceiverParameterDescriptor receiverDescriptor = null; ReceiverParameterDescriptor receiverDescriptor = null;
if (receiverTypeRef != null) {
receiverType = typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, receiverTypeRef, trace, true);
AnnotationSplitter splitter = new AnnotationSplitter(storageManager, receiverType.getAnnotations(), EnumSet.of(RECEIVER));
receiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable(
propertyDescriptor, receiverType, splitter.getAnnotationsForTarget(RECEIVER)
);
}
List<KtContextReceiver> contextReceivers = variableDeclaration.getContextReceivers();
List<ReceiverParameterDescriptor> contextReceiverDescriptors = IntStream.range(0, contextReceivers.size()).mapToObj(index -> {
KtContextReceiver contextReceiver = contextReceivers.get(index);
KtTypeReference typeReference = contextReceiver.typeReference();
if (typeReference == null) {
return null;
}
KotlinType type = typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, typeReference, trace, true);
AnnotationSplitter splitter = new AnnotationSplitter(storageManager, type.getAnnotations(), EnumSet.of(RECEIVER));
return DescriptorFactory.createContextReceiverParameterForCallable(
propertyDescriptor, type, contextReceiver.labelNameAsName(), splitter.getAnnotationsForTarget(RECEIVER), index
);
}).collect(Collectors.toList());
if (languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers)) {
Multimap<String, ReceiverParameterDescriptor> nameToReceiverMap = HashMultimap.create();
if (receiverTypeRef != null) { if (receiverTypeRef != null) {
String receiverName = receiverTypeRef.nameForReceiverLabel(); receiverType = typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, receiverTypeRef, trace, true);
if (receiverName != null) { AnnotationSplitter splitter = new AnnotationSplitter(storageManager, receiverType.getAnnotations(), EnumSet.of(RECEIVER));
nameToReceiverMap.put(receiverName, receiverDescriptor); receiverDescriptor = DescriptorFactory.createExtensionReceiverParameterForCallable(
} propertyDescriptor, receiverType, splitter.getAnnotationsForTarget(RECEIVER)
);
} }
for (int i = 0; i < contextReceivers.size(); i++) {
String contextReceiverName = contextReceivers.get(i).name(); List<KtContextReceiver> contextReceivers = variableDeclaration.getContextReceivers();
if (contextReceiverName != null) { List<ReceiverParameterDescriptor> contextReceiverDescriptors = IntStream.range(0, contextReceivers.size()).mapToObj(index -> {
nameToReceiverMap.put(contextReceiverName, contextReceiverDescriptors.get(i)); KtContextReceiver contextReceiver = contextReceivers.get(index);
KtTypeReference typeReference = contextReceiver.typeReference();
if (typeReference == null) {
return null;
} }
KotlinType type = typeResolver.resolveType(scopeForDeclarationResolutionWithTypeParameters, typeReference, trace, true);
AnnotationSplitter splitter = new AnnotationSplitter(storageManager, type.getAnnotations(), EnumSet.of(RECEIVER));
return DescriptorFactory.createContextReceiverParameterForCallable(
propertyDescriptor, type, contextReceiver.labelNameAsName(), splitter.getAnnotationsForTarget(RECEIVER), index
);
}).collect(Collectors.toList());
if (languageVersionSettings.supportsFeature(LanguageFeature.ContextReceivers)) {
Multimap<String, ReceiverParameterDescriptor> nameToReceiverMap = HashMultimap.create();
if (receiverTypeRef != null) {
String receiverName = receiverTypeRef.nameForReceiverLabel();
if (receiverName != null) {
nameToReceiverMap.put(receiverName, receiverDescriptor);
}
}
for (int i = 0; i < contextReceivers.size(); i++) {
String contextReceiverName = contextReceivers.get(i).name();
if (contextReceiverName != null) {
nameToReceiverMap.put(contextReceiverName, contextReceiverDescriptors.get(i));
}
}
trace.record(DESCRIPTOR_TO_CONTEXT_RECEIVER_MAP, propertyDescriptor, nameToReceiverMap);
} }
trace.record(DESCRIPTOR_TO_CONTEXT_RECEIVER_MAP, propertyDescriptor, nameToReceiverMap);
}
LexicalScope scopeForInitializer = ScopeUtils.makeScopeForPropertyInitializer(scopeForInitializerResolutionWithTypeParameters, propertyDescriptor); LexicalScope scopeForInitializer = ScopeUtils.makeScopeForPropertyInitializer(scopeForInitializerResolutionWithTypeParameters, propertyDescriptor);
KotlinType propertyType = propertyInfo.getVariableType(); KotlinType propertyType = propertyInfo.getVariableType();
KotlinType typeIfKnown = propertyType != null ? propertyType : variableTypeAndInitializerResolver.resolveTypeNullable( KotlinType typeIfKnown = propertyType != null ? propertyType : variableTypeAndInitializerResolver.resolveTypeNullable(
propertyDescriptor, scopeForInitializer, propertyDescriptor, scopeForInitializer,
variableDeclaration, dataFlowInfo, inferenceSession, variableDeclaration, dataFlowInfo, inferenceSession,
trace, /* local = */ false trace, /* local = */ false
); );
PropertyGetterDescriptorImpl getter = resolvePropertyGetterDescriptor( PropertyGetterDescriptorImpl getter = resolvePropertyGetterDescriptor(
scopeForDeclarationResolutionWithTypeParameters, scopeForDeclarationResolutionWithTypeParameters,
variableDeclaration, variableDeclaration,
propertyDescriptor, propertyDescriptor,
annotationSplitter, annotationSplitter,
trace, trace,
typeIfKnown, typeIfKnown,
propertyInfo.getPropertyGetter(), propertyInfo.getPropertyGetter(),
propertyInfo.getHasDelegate(), propertyInfo.getHasDelegate(),
inferenceSession inferenceSession
); );
KotlinType type = typeIfKnown != null ? typeIfKnown : getter.getReturnType(); KotlinType type = typeIfKnown != null ? typeIfKnown : getter.getReturnType();
assert type != null : "At least getter type must be initialized via resolvePropertyGetterDescriptor"; assert type != null : "At least getter type must be initialized via resolvePropertyGetterDescriptor";
variableTypeAndInitializerResolver.setConstantForVariableIfNeeded( variableTypeAndInitializerResolver.setConstantForVariableIfNeeded(
propertyDescriptor, scopeForInitializer, variableDeclaration, dataFlowInfo, type, inferenceSession, trace propertyDescriptor, scopeForInitializer, variableDeclaration, dataFlowInfo, type, inferenceSession, trace
); );
propertyDescriptor.setType(type, typeParameterDescriptors, getDispatchReceiverParameterIfNeeded(container), receiverDescriptor, propertyDescriptor.setType(type, typeParameterDescriptors, getDispatchReceiverParameterIfNeeded(container), receiverDescriptor,
contextReceiverDescriptors); contextReceiverDescriptors);
PropertySetterDescriptor setter = resolvePropertySetterDescriptor( PropertySetterDescriptor setter = resolvePropertySetterDescriptor(
scopeForDeclarationResolutionWithTypeParameters, scopeForDeclarationResolutionWithTypeParameters,
variableDeclaration, variableDeclaration,
propertyDescriptor, propertyDescriptor,
annotationSplitter, annotationSplitter,
trace, trace,
propertyInfo.getPropertySetter(), propertyInfo.getPropertySetter(),
propertyInfo.getHasDelegate(), propertyInfo.getHasDelegate(),
inferenceSession inferenceSession
); );
propertyDescriptor.initialize( propertyDescriptor.initialize(
getter, setter, getter, setter,
new FieldDescriptorImpl(annotationSplitter.getAnnotationsForTarget(FIELD), propertyDescriptor), new FieldDescriptorImpl(annotationSplitter.getAnnotationsForTarget(FIELD), propertyDescriptor),
new FieldDescriptorImpl(annotationSplitter.getAnnotationsForTarget(PROPERTY_DELEGATE_FIELD), propertyDescriptor) new FieldDescriptorImpl(annotationSplitter.getAnnotationsForTarget(PROPERTY_DELEGATE_FIELD), propertyDescriptor)
); );
trace.record(BindingContext.VARIABLE, variableDeclaration, propertyDescriptor); trace.record(BindingContext.VARIABLE, variableDeclaration, propertyDescriptor);
return propertyDescriptor; return propertyDescriptor;
});
} }
@NotNull @NotNull