DeepWiki-found bugs

Đang mở
#382 2 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
38/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Ít trao đổi
Công nghệ
csharp
Lĩnh vực
backend

Hướng nghiên cứu

Rà soát tám điểm đầu vào đã được báo cáo, đặc biệt là OverridesLing_MoClasses.cs, ScrTxtPara.cs, CmObject.cs, UnitOfWorkService.cs, XmlImportData.cs, ITextUtils.cs và FileTransactionLogger.cs. Xác thực từng phát hiện dựa trên mã xung quanh và các bài kiểm thử hiện có; hoàn tất nghĩa là các lỗi đã chọn được xác nhận, sửa chữa và bao phủ bởi các bài kiểm thử hồi quy phù hợp.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

https://deepwiki.com/sillsdev/liblcm
https://deepwiki.com/search/find-bugs_563f89be-f25d-46f1-9d57-0afdf13b424c?mode=deep

Here are the bugs found across the codebase, ordered roughly by severity:


Bug 1: NullReferenceException in MoMorphData.ActiveParser setter

File: src/SIL.LCModel/DomainImpl/OverridesLing_MoClasses.cs

(L4218-4234)
				XmlDocument doc = new XmlDocument();
				XmlNode paramsNode = null;
				try
				{
					doc.LoadXml(ParserParameters);
					paramsNode = doc.SelectSingleNode("/ParserParameters");
				}
				catch
				{
					// Eat exception.
				}

				if (paramsNode == null)
				{
					paramsNode = doc.CreateElement("ParserParameters");
					doc.DocumentElement.AppendChild(paramsNode);
				}

When doc.LoadXml(ParserParameters) throws (e.g., ParserParameters is null or malformed XML), the exception is silently swallowed and paramsNode stays null. The code then calls doc.DocumentElement.AppendChild(paramsNode), but doc.DocumentElement is null on a freshly constructed XmlDocument, causing a NullReferenceException. The fix is doc.AppendChild(paramsNode).


Bug 2: Skipped run after removal in CleanChapterInBtPara

File: src/SIL.LCModel/DomainImpl/ScrTxtPara.cs

(L1751-1760)
		private void CleanChapterInBtPara(int wsAlt, BCVRef startRef, BCVRef endRef)
		{
			int iRun = 0;

			while (iRun < GetOrCreateBT().Translation.get_String(wsAlt).RunCount)
			{
				RemoveOutOfRangeChapterRun(iRun, wsAlt, startRef, endRef);
				iRun++;
			}
		}

iRun is unconditionally incremented even when RemoveOutOfRangeChapterRun returns true (meaning a run was deleted and all subsequent runs shifted down by one). The run that slides into position iRun is never examined. Two consecutive out-of-range chapter runs will cause the second one to be silently skipped.


Bug 3: Potential NullReferenceException in MergeSelectedPropertiesOfObject

File: src/SIL.LCModel/DomainImpl/CmObject.cs

(L1058-1060)
							var myAddMethod = myCurrentValue.GetType().GetMethod("Add");
							foreach (var input in ((ILcmVector)srcCurrentValue).Objects)
								myAddMethod.Invoke(myCurrentValue, new object[] { input });

myCurrentValue.GetType().GetMethod("Add") can return null if the runtime type doesn't expose a public Add method with the expected signature (e.g., due to explicit interface implementation). The result is used immediately without a null check, so myAddMethod.Invoke(...) will throw a NullReferenceException.


Bug 4: Silent data loss in CollectVars for sequence contexts

File: src/SIL.LCModel/DomainImpl/OverridesLing_MoClasses.cs

(L4157-4161)
				case PhSequenceContextTags.kClassId:
					var seqCtxt = (IPhSequenceContext)ctxt;
					foreach (var cur in seqCtxt.MembersRS)
						CollectVars(cur as IPhSimpleContextNC, featureConstrs);
					break;

In the PhSequenceContextTags.kClassId case, each member is cast with cur as IPhSimpleContextNC. If a member is not an IPhSimpleContextNC (e.g., it is a PhIterationContext or PhSequenceContext), the cast silently returns null, and the null-guard at the top of CollectVars returns early — those members' variables are never collected.


Bug 5: Managed object access from finalizer in UnitOfWorkService.Dispose

File: src/SIL.LCModel/Infrastructure/Impl/UnitOfWorkService.cs

(L215-223)
			if (fDisposing && !IsDisposed)
			{
				// dispose managed and unmanaged objects
				m_lock.Dispose();
				m_saveTimer.Dispose();
			}
			IsDisposed = true;
			m_logger?.AddBreadCrumb("UOW Disposed.");
		}

m_logger?.AddBreadCrumb("UOW Disposed.") is placed outside the if (fDisposing && !IsDisposed) guard. When called from the finalizer (fDisposing == false), this accesses the managed m_logger object, which may already have been garbage-collected. This violates the standard dispose pattern and can cause unpredictable behavior.


Bug 6: NullReferenceException in WsString.Equals and GetHashCode

File: src/SIL.LCModel/Application/ApplicationServices/XmlImportData.cs

(L2492-2507)
			public override bool Equals(object obj)
			{
				if (obj is WsString)
				{
					return (ws == ((WsString)obj).ws) && sVal.Equals(((WsString)obj).sVal);
				}
				else
				{
					return false;
				}
			}

			public override int GetHashCode()
			{
				return sVal.GetHashCode() + (ws % 100);
			}

WsString.Equals calls sVal.Equals(...) and GetHashCode calls sVal.GetHashCode() without guarding against sVal being null. If a WsString is constructed with a null string value, both methods will throw NullReferenceException.


Bug 7: Wrong exception type in IndexOfFirstUnusedId

File: src/SIL.LCModel/DomainServices/ITextUtils.cs

(L875-880)
		static protected int IndexOfFirstUnusedId(List<int> ids)
		{
			if (ids == null)
				throw new NullReferenceException("ids");
			return IndexOfFirstUnusedId(ids.ToArray());
		}

The method explicitly throws new NullReferenceException("ids") for a null argument. This should be ArgumentNullException, which is the standard .NET convention for null parameter validation. NullReferenceException is reserved for unintentional null dereferences.


Bug 8: Potential deadlock in FileTransactionLogger finalizer

File: src/SIL.LCModel/FileTransactionLogger.cs

(L41-56)
	   protected virtual void Dispose(bool disposing)
		{
			Debug.WriteLineIf(!disposing, "****** Missing Dispose() call for " + GetType() + ". *******");
			lock (m_lock)
			{
				if (!m_disposed)
				{
					try { m_lastWrite?.GetAwaiter().GetResult(); }
					catch { /* best-effort: don't let a failed write prevent disposal */ }
					m_stream?.Flush();
					m_stream?.Dispose();
					m_stream = null;
					m_disposed = true;
				}
			}
		}

The finalizer calls Dispose(false), which acquires m_lock and then calls m_lastWrite?.GetAwaiter().GetResult(). Blocking on a Task from a finalizer thread is dangerous: if the continuation was scheduled to run on the finalizer thread (via ExecuteSynchronously), it cannot run while the finalizer thread is blocked waiting for it — a deadlock. The finalizer path should skip the GetResult() call entirely.

Ngôn ngữ chính
C#
Star
3
Fork
15
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của sillsdev/liblcm

Tất cả issue của sillsdev/liblcm

Issue tương tự

Thêm issue về C#

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.