【问题标题】:Delphi JSONArray SetJSONValue access violationDelphi JSONArray SetJSONValue 访问冲突
【发布时间】:2015-11-11 12:18:38
【问题描述】:

我有一个 JSONArray 作为参数传递给我的服务器。我有一个由“生成数据快照客户端类”过程生成的方法,当它到达第一个“SetJsonValue”行时,它给了我一个访问冲突,这个错误来来去去,没有明显的原因。我在 LAN 中使用了一个 Rest 服务器(也将它与 http 一起使用,但尚未对其进行测试)。有时它可以通过重新启动我的计算机/编译器来解决,但有时它会持续更长时间。

方法如下:

if FExecutaInsertCommand = nil then
begin
  FExecutaInsertCommand := FConnection.CreateCommand;
  FExecutaInsertCommand.RequestType := 'POST';
  FExecutaInsertCommand.Text := 'TServerMethods."ExecutaInsert"';
  FExecutaInsertCommand.Prepare(TServerMethods_ExecutaInsert);
end;
FExecutaInsertCommand.Parameters[0].Value.SetWideString(database);
FExecutaInsertCommand.Parameters[1].Value.SetWideString(Tabela);
FExecutaInsertCommand.Parameters[2].Value.SetJSONValue(aValores,   FInstanceOwner);
FExecutaInsertCommand.Parameters[3].Value.SetJSONValue(aTipos,   FInstanceOwner);
FExecutaInsertCommand.Parameters[4].Value.SetInt32(usuario);
FExecutaInsertCommand.Execute(ARequestFilter);
Result := FExecutaInsertCommand.Parameters[5].Value.GetInt32;

从这里调用方法:

result := DMClient.ServerMethodsClient.ExecutaInsert(banco, Tabela, GeraJSONArray(Registro), GeraJSONArray(GetStrings(Registro.DataType)), CodigoUsuarioLogado);

JSONArray 的生成方式如下:

function GeraJSONArray(Valores: TVariantArray) : TJSONArray;
var
  i : Integer;
begin
  result := TJSONArray.Create;
  for i := 0 to Length(Valores.Values) - 1 do
    result.Adiciona(Valores.Values[i], Valores.DataType[i]);
end;

function GeraJSONArray(Valores: TArray<String>) : TJSONArray;
var
  i : Integer;
begin
  result := TJSONArray.Create;
  for i := 0 to Length(Valores) - 1 do
    result.AddElement(TJSONString.Create(Valores[i]));
end;

JsonArray.Adiciona:

procedure TJSONArrayHelper.Adiciona(valor: variant; DataType: TFieldType);
var
  JSONValue : TJSONValue;
begin
  if not (VarIsEmpty(valor)) and not (VarIsNull(valor)) then
  begin
    case DataType of 
      TFieldType.ftString,
      TFieldType.ftMemo,
      TFieldType.ftFmtMemo,
      TFieldType.ftFixedChar,
      TFieldType.ftWideString : JSONValue := TJSONString.Create(valor);
      //-----------------------------------------------//
      TFieldType.ftSmallint,
      TFieldType.ftInteger,
      TFieldType.ftWord,
      TFieldType.ftFloat,
      TFieldType.ftCurrency,
      TFieldType.ftAutoInc,
      TFieldType.ftLargeint,
      TFieldType.ftSingle,
      TFieldType.ftBCD : JSONValue := TJSONNumber.Create(valor);
      //-----------------------------------------------//
      TFieldType.ftDateTime : JSONValue :=     TJSONString.Create(DateTimeParaString(valor));
    end;
  end
  else
  begin
    JSONValue := TJSONNull.Create;
  end;
  if JSONValue <> nil then
    AddElement(JSONValue);
end;

参数2产生错误,但参数3没有,我认为Adiciona程序有问题

【问题讨论】:

  • 请将其缩减为minimal reproducible example。使用 FastMM 帮助自己使缺陷更可重复。
  • 我认为最好在 Destroy 中添加一个测试:if FMembers[I] is TJSONAncestor。可能有一个意想不到的不同类型,甚至某些元素是 Nil。
  • @Christian,显示的Destroy 方法是Delphi 提供的一种;修改它并非易事。此外,几乎不值得修改代码以在调试器中轻松检查而无需额外代码。该修复将首先防止无效项目进入数组,一旦它们在那里就不会跳过它们。此外,该元素不为空; Ricardo 之前对这个问题的尝试表明访问冲突的正常外观非零地址。
  • Ricardo,您的第一个GeraJSONArray 函数调用TJSONArray.Adiciona,这不是该类型的标准方法。请确保在 David 请求的示例中包含该方法。
  • Adiciona 检查数据类型,创建一个 JSONObject 来保存它并调用 self.Add

标签: arrays json rest delphi datasnap


【解决方案1】:

在您的Adiciona 方法中,如果DataType 不是您的case 语句中列出的任何值,那么您的本地JSONValue 变量将保持未初始化状态。特别要注意,该变量的默认值是 not nil — 本地对象引用变量没有默认值 — 所以请在方法末尾检查 JSONValue &lt;&gt; nil这是一个无意义的比较。

documentation lists 52 possible TFieldType values;您的代码仅处理 15 个。您可以使用 else 子句来说明剩余的内容:

case DataType of
  ...
  else raise Exception.CreateFmt('Unexpected field type (%d)', [Ord(DataType)]);

编译器应该警告您该变量可能未初始化,尽管该警告所需的分析不可能完美,因此编译器可能无法检测到这种情况。如果编译器警告了你而你忽略了警告,那就让这成为你的一个教训。

将未初始化的对象引用添加到数组时,我们可能期望的行为与您观察到的访问冲突异常一致。析构函数将从数组中获取未初始化的值并尝试在其上调用GetOwned。在不是对象引用的事物上调用方法可能会导致许多问题; 最好的是你现在所看到的,这是一个例外,会立即告诉你有问题。 (想想如果程序默默地继续运行会有多糟糕。谁知道如果析构函数的 Member.Free 调用已经运行并实际上破坏了程序中的其他东西,你会看到什么奇怪的问题?)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多