From b16eab8f335a4c17850b77f1f896c29b8632cf6e Mon Sep 17 00:00:00 2001 From: Jakob Rath <git@jakobrath.eu> Date: Mon, 16 Dec 2013 21:00:59 +0100 Subject: [PATCH] Fix memory issues, add HBytes#token. --- src/bindings/ruby/lib/hammer.rb | 3 +++ src/bindings/ruby/lib/hammer/internal.rb | 5 +++++ src/bindings/ruby/lib/hammer/parser.rb | 18 +++++++++++++++--- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/bindings/ruby/lib/hammer.rb b/src/bindings/ruby/lib/hammer.rb index bb0e2a2d..cfb62dcb 100644 --- a/src/bindings/ruby/lib/hammer.rb +++ b/src/bindings/ruby/lib/hammer.rb @@ -16,4 +16,7 @@ parser = Hammer::Parser.build { } x.bind(Hammer::Parser.token('abd')) +#$p = parser $r = parser.parse 'abcabd' + +p $r[:ast][:data][:seq].elements.map {|e| e[:data][:bytes].token } diff --git a/src/bindings/ruby/lib/hammer/internal.rb b/src/bindings/ruby/lib/hammer/internal.rb index 8f673d4e..0c462fe2 100644 --- a/src/bindings/ruby/lib/hammer/internal.rb +++ b/src/bindings/ruby/lib/hammer/internal.rb @@ -37,6 +37,11 @@ module Hammer class HBytes < FFI::Struct layout :token, :pointer, # uint8_t* :len, :size_t + + def token + # TODO: Encoding? Should probably be the same encoding as the string the token was created with. + return self[:token].read_string(self[:len]) #.force_encoding('UTF-8') + end end class HParsedTokenDataUnion < FFI::Union diff --git a/src/bindings/ruby/lib/hammer/parser.rb b/src/bindings/ruby/lib/hammer/parser.rb index 1d7a76ed..c0c1cfc8 100644 --- a/src/bindings/ruby/lib/hammer/parser.rb +++ b/src/bindings/ruby/lib/hammer/parser.rb @@ -7,10 +7,12 @@ module Hammer # name: Name of the parser. Should be a symbol. # h_parser: The pointer to the parser as returned by hammer. # dont_gc: Pass additional data that's used by the parser and needs to be saved from the garbage collector (at least as long this object lives). - def initialize(name, h_parser, dont_gc) + def initialize(name, h_parser, dont_gc=[]) @name = name @h_parser = h_parser - @dont_gc = dont_gc + # Always store as array, so we can easily add stuff later on + dont_gc = [dont_gc] unless dont_gc.is_a? Array + @dont_gc = dont_gc.dup end attr_reader :name @@ -24,13 +26,23 @@ module Hammer raise ArgumentError, 'expecting a String' unless data.is_a? String # TODO: Not needed, FFI checks that. result = Hammer::Internal.h_parse(@h_parser, data, data.bytesize) - return result unless result.null? + if result.null? + return nil + else + # NOTE: + # The parse result *must* hold a reference to the parser that created it! + # Otherwise, the parser might get garbage-collected while the result is still valid. + # Any pointers to token strings will then be invalid. + result.instance_variable_set :@parser, self + return result + end end # Binds an indirect parser. def bind(other_parser) raise RuntimeError, 'can only bind indirect parsers' unless self.name == :indirect Hammer::Internal.h_bind_indirect(self.h_parser, other_parser.h_parser) + @dont_gc << other_parser end def self.token(string) -- GitLab