当SBValue来自Swift字典时SBData错误 [英] SBData is wrong when SBValue comes from a Swift Dictionary

查看:50
本文介绍了当SBValue来自Swift字典时SBData错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正试图编写一个Python函数来格式化Foundation.Decimal,以用作类型汇总器.我将其发布在此答案中.我还将在答案的底部将其包括在内,并附带其他调试信息.

I'm trying to write a Python function to format a Foundation.Decimal, for use as a type summarizer. I posted it in this answer. I'll also include it at the bottom of this answer, with extra debug prints.

我现在已经发现了一个错误,但是我不知道该错误是在我的函数中,还是在lldb中,或者可能是在Swift编译器中.

I've now discovered a bug, but I don't know if the bug is in my function, or in lldb, or possibly in the Swift compiler.

下面是一个演示该错误的记录.我在~/.lldbinit中加载了类型汇总器,因此Swift REPL会使用它.

Here's a transcript that demonstrates the bug. I load my type summarizer in ~/.lldbinit, so the Swift REPL uses it.

:; xcrun swift
registering Decimal type summaries
Welcome to Apple Swift version 4.2 (swiftlang-1000.11.37.1 clang-1000.11.45.1). Type :help for assistance.
  1> import Foundation
  2> let dec: Decimal = 7
dec: Decimal = 7

上面,调试器输出中的7来自我的类​​型汇总器,并且是正确的.

Above, the 7 in the debugger output is from my type summarizer and is correct.

  3> var dict = [String: Decimal]()
dict: [String : Decimal] = 0 key/value pairs
  4> dict["x"] = dec
  5> dict["x"]
$R0: Decimal? = 7

上面,7还是来自我的类​​型汇总器,并且是正确的.

Above, the 7 is again from my type summarizer, and is correct.

  6> dict
$R1: [String : Decimal] = 1 key/value pair {
  [0] = {
    key = "x"
    value = 0
  }
}

以上,0(在value = 0中)来自我的类​​型汇总器,并且不正确.应该是7.

Above, the 0 (in value = 0) is from my type summarizer, and is incorrect. It should be 7.

那为什么它为零?我的Python函数被赋予SBValue.它在SBValue上调用GetData()以获得SBData.我在函数中添加了调试打印,以打印SBData中的字节,并打印sbValue.GetLoadAddress()的结果.这是带有这些调试打印记录的文字记录:

So why is it zero? My Python function is given an SBValue. It calls GetData() on the SBValue to get an SBData. I added debug prints to the function to print the bytes in the SBData, and also to print the result of sbValue.GetLoadAddress(). Here's the transcript with these debug prints:

:; xcrun swift
registering Decimal type summaries
Welcome to Apple Swift version 4.2 (swiftlang-1000.11.37.1 clang-1000.11.45.1). Type :help for assistance.
  1> import Foundation
  2> let dec: Decimal = 7
dec: Decimal =    loadAddress: ffffffffffffffff
    data: 00 21 00 00 07 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 7

上面,我们可以看到加载地址是伪造的,但是SBData的字节是正确的(字节1,21,包含长度和标志;字节4,'07',是第一个字节)的有效数字.

Above, we can see that the load address is bogus, but the bytes of the SBData are correct (byte 1, 21, contains the length and flags; byte 4, '07', is the first byte of the significand).

  3> var dict = [String: Decimal]()
dict: [String : Decimal] = 0 key/value pairs
  4> dict["x"] = dec
  5> dict
$R0: [String : Decimal] = 1 key/value pair {
  [0] = {
    key = "x"
    value =    loadAddress: ffffffffffffffff
    data: 00 00 00 00 00 21 00 00 07 00 00 00 00 00 00 00 00 00 00 00
 0
  }
}

上面,我们可以看到加载地址仍然是伪造的,现在SBData的字节不正确. SBData仍然包含20个字节(Foundation.Decimal的正确数字,也称为NSDecimal),但是现在在前面插入了四个00字节,而最后四个字节被删除了.

Above, we can see that the load address is still bogus, and now the bytes of the SBData are incorrect. The SBData still contains 20 bytes (the correct number for a Foundation.Decimal, aka NSDecimal), but now four 00 bytes have been inserted at the front and the last four bytes have been dropped.

这是我的具体问题:

  1. 我错误地使用了lldb API,因此得到了错误的答案吗?如果是这样,我在做什么错,应该如何纠正?

  1. Am I using the lldb API incorrectly, and thus getting wrong answers? If so, what am I doing wrong and how should I correct it?

如果我正确使用了lldb API,那么这是lldb中的错误,还是Swift编译器发出了不正确的元数据?我如何找出哪个工具有此错误? (因为这是其中一种工具的错误,我想提交一个错误报告.)

If I'm using the lldb API correctly, then is this a bug in lldb, or is the Swift compiler emitting incorrect metadata? How can I figure out which tool has the bug? (Because if it's a bug in one of the tools, I'd like to file a bug report.)

如果这是lldb或Swift中的错误,如何解决该问题,以便当Decimal属于Dictionary时可以正确格式化Decimal?

If it's a bug in lldb or Swift, how can I work around the problem so I can format a Decimal correctly when it's part of a Dictionary?


这是我的类型格式化程序,带有调试打印:


Here is my type formatter, with debug prints:

# Decimal / NSDecimal support for lldb
#
# Put this file somewhere, e.g. ~/.../lldb/Decimal.py
# Then add this line to ~/.lldbinit:
#     command script import ~/.../lldb/Decimal.py

import lldb

def stringForDecimal(sbValue, internal_dict):
    from decimal import Decimal, getcontext

    print('    loadAddress: %x' % sbValue.GetLoadAddress())

    sbData = sbValue.GetData()
    if not sbData.IsValid():
        raise Exception('unable to get data: ' + sbError.GetCString())
    if sbData.GetByteSize() != 20:
        raise Exception('expected data to be 20 bytes but found ' + repr(sbData.GetByteSize()))

    sbError = lldb.SBError()
    exponent = sbData.GetSignedInt8(sbError, 0)
    if sbError.Fail():
        raise Exception('unable to read exponent byte: ' + sbError.GetCString())

    flags = sbData.GetUnsignedInt8(sbError, 1)
    if sbError.Fail():
        raise Exception('unable to read flags byte: ' + sbError.GetCString())
    length = flags & 0xf
    isNegative = (flags & 0x10) != 0

    debugString = ''
    for i in range(20):
        debugString += ' %02x' % sbData.GetUnsignedInt8(sbError, i)
    print('    data:' + debugString)

    if length == 0 and isNegative:
        return 'NaN'

    if length == 0:
        return '0'

    getcontext().prec = 200
    value = Decimal(0)
    scale = Decimal(1)
    for i in range(length):
        digit = sbData.GetUnsignedInt16(sbError, 4 + 2 * i)
        if sbError.Fail():
            raise Exception('unable to read memory: ' + sbError.GetCString())
        value += scale * Decimal(digit)
        scale *= 65536

    value = value.scaleb(exponent)
    if isNegative:
        value = -value

    return str(value)

def __lldb_init_module(debugger, internal_dict):
    print('registering Decimal type summaries')
    debugger.HandleCommand('type summary add Foundation.Decimal -F "' + __name__ + '.stringForDecimal"')
    debugger.HandleCommand('type summary add NSDecimal -F "' + __name__ + '.stringForDecimal"')

推荐答案

这看起来像是lldb错误.请使用 http://bugs.swift.org 针对lldb提交有关此问题的错误.

This looks like an lldb bug. Please file a bug about this against lldb with http://bugs.swift.org.

对于背景:在字典的情况下,背后有一些魔力.我无法在REPL中显示此信息,但是如果您有[String:Decimal]数组作为某些实际代码中的局部变量,请执行以下操作:

For background: there is some magic going on behind your back in the Dictionary case. I can't show this in the REPL, but if you have a [String : Decimal] array as a local variable in some real code and do:

(lldb) frame variable --raw dec_array
(Swift.Dictionary<Swift.String, Foundation.Decimal>) dec_array = {
  _variantBuffer = native {
    native = {
      _storage = 0x0000000100d05780 {
        Swift._SwiftNativeNSDictionary = {}
        bucketCount = {
          _value = 2
        }
        count = {
          _value = 1
        }
        initializedEntries = {
          values = {
            _rawValue = 0x0000000100d057d0
          }
          bitCount = {
            _value = 2
          }
        }
        keys = {
          _rawValue = 0x0000000100d057d8
        }
        values = {
          _rawValue = 0x0000000100d057f8
        }
        seed = {
          0 = {
            _value = -5794706384231184310
          }
          1 = {
            _value = 8361200869849021207
          }
        }
      }
    }
    cocoa = {
      cocoaDictionary = 0x00000001000021b0
    }
  }
}

快速的字典实际上不包含任何明显的字典元素,当然也没有ivars.因此lldb为Swift字典提供了一个合成子提供程序",它为字典的键和值组成了SBValues,并且它是格式化程序要处理的那些合成子之一.

A swift Dictionary doesn't actually contain the dictionary elements anywhere obvious, and certainly not as ivars. So lldb has a "Synthetic child provider" for Swift Dictionaries that makes up SBValues for the keys and values of the Dictionary, and it is one of those synthetic children that your formatter is being handed.

这也是加载地址为-1的原因.这确实意味着这是一个由数据lldb直接管理的合成事物,而不是程序中某个地址的事物." REPL结果也是如此,它们更多是lldb维护的小说.但是,如果查看Decimal类型的局部变量,则会看到一个有效的加载地址,因为它是存在于内存中某处的东西.

That's also why the load address is -1. That really means "this is a synthetic thing whose data lldb is directly managing, not a thing at an address somewhere in your program." The same thing is true of REPL results, they are more a fiction lldb maintains. But if you looked at a local variable of type Decimal, you would see a valid load address, because it is a thing that lives somewhere in memory.

无论如何,显然我们为表示字典值而组成的Synthetic children Decimal对象不能正确设置数据的开头.有趣的是,如果您制作了[Decimal:String]字典,则关键字段的SBData是正确的,并且格式化程序可以正常工作.只是不正​​确的值.

Anyway, so apparently the Synthetic children Decimal objects we are making up to represent the values of the dictionary don't set the start of the data correctly. Interestingly enough, if you make a [Decimal : String] dictionary, the key field's SBData is correct, and your formatter works. It's just the values that aren't right.

我用字典作为字符串作为值尝试了同样的事情,并且SBData在这里看起来是正确的.因此,十进制有一些有趣的地方.无论如何,感谢您的追求,请提交错误.

I tried the same thing with Dictionaries that have Strings as values, and the SBData looks correct there. So there's something funny about Decimal. Anyway, thanks for pursuing this, and please do file a bug.

这篇关于当SBValue来自Swift字典时SBData错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆