Обнаружение изменения или повреждения структуры или хэш-таблицы - PullRequest
0 голосов
/ 21 ноября 2018

Есть ли в Common Lisp какие-либо инструменты, которые можно использовать для отладки условия по следующим строкам?

Существует хеш-таблица, которая модифицируется (одно из значений ключа обращается в NIL), и я пытаюсь ее отладить.Я смог сузить его до того места, где оно предположительно происходит, но таблица не модифицируется явно через официальные средства доступа.

Я не могу опубликовать код, потому что он проприетарный.

1 Ответ

0 голосов
/ 23 ноября 2018

Я бы предложил две вещи.Первый - попытаться отследить функцию, которая модифицирует хеш-таблицы.Это (setf gethash) за исключением того, что gethash является аксессором , а не функцией .Чтобы выяснить, какая функция используется реализацией для обновления хеш-таблицы, выполните, например,

(disassemble (compile (defun foo (x y) (setf (gethash x y) t))))

, которая показывает код сборки, который должен содержать вызов внутренней функции с именем, подобным puthash.

Действие (trace puthash) может привести к проблеме, так как реализация может обновить хэш-таблицу как часть этого вызова.Но если предположить, что это работает, это может показать вам, где происходит неожиданное обновление хеш-таблицы.

Некоторые реализации расширили функциональность trace.Например, Allegro CL предлагает множество опций трассировки .Например, если ваши функции называются foo и bar, и вы хотите видеть вызовы excl::%puthash из этих функций, вы скажете:

(trace (excl::%puthash :inside (foo bar))

и если вы хотите увидеть, чтоконтекст вызова включает бит стека:

cl-user(1): (trace (excl::%puthash :inside foo :show-stack 3))
(excl::%puthash)
cl-user(2): (setf (gethash 3 (make-hash-table)) 2)
;; Note: no trace output, because not in foo
2
cl-user(3): (foo 3 (make-hash-table))
;; Note: within foo, so trace output which includes 3 stack frames
 0[2]: (excl::%puthash 3 #<eql hash-table with 0 entries @ #x100192cfa72> t)
 0^      <- (system::..runtime-operation "fwrap_start" 3 #<eql hash-table with 0 entries @ #x100192cfa72> t)
 0^      <- (foo 3 #<eql hash-table with 0 entries @ #x100192cfa72>)
 0^      <- (eval (foo 3 (make-hash-table)))
 0[2]: returned t
t

Трассировка, подобная этой, может быть чрезвычайно полезна при работе с неизвестным кодом.

Второе, что нужно сделать, это проверитькод, чтобы убедиться, что ключи, хранящиеся в хэш-таблице, не изменены.Например,

(let ((x (list 1 2))
      (ht (make-hash-table :test 'equal))
   (setf (gethash x ht) t)
   (setf (car x) 10) ;; not allowed!
   (gethash x ht)) ;; now in a funny state: may return T, or nil

См. 18.1.2 Изменение ключей хеш-таблицы .Более того, литеральные объекты также не могут быть изменены, что также может быть причиной странностей:

(let ((x '(1 2)))
   (setf (car x) 10) ;; not allowed!
...