Segmentation fault on Lion creating NSData from RubyCocoa with any bytes > 127 - ruby

The following RubyCocoa is fine on Max OS X 10.6, but segfaults on 10.7
require 'osx/cocoa'
include OSX
bytes = [128].pack('i1')
NSData.alloc.initWithBytes_length(bytes, bytes.length)
In all cases it works when the top bit is not set. In fact NSData.alloc seems to fail when passed a buffer where any of the bytes have the top bit set.
The version of Ruby is 1.8.7 on both OS's, so I'm at a loss to diagnose why NSData is interpreting the buffer differently. Can anyone shed any light?

You should probably go for MacRuby as it will replace RubyCocoa. It's possible that RubyCocoa does not (and will never) work properly on Lion.
I don't have any MacRuby experience with Lion yet, but chances are good that it will work.

MacRuby is still unfinished - it just doesn't work with some of the ruby code I work with.
I've run into the same NSData problem, and I was able to create a CFData instance which appears ok with the following code
gem 'RubyInline'
require 'inline'
class CFDataWrapper
begin
inline do |builder|
builder.include "<CoreFoundation/CoreFoundation.h>"
builder.c_raw_singleton "
static VALUE fromString(int argc, VALUE *args){
CFDataRef d = CFDataCreate(NULL, RSTRING_PTR(args[0]), RSTRING_LEN(args[0]));
VALUE result;
char type = '#';
ocdata_to_rbobj(Qnil,&type, (const void *)&d, &result, false) ;
return result;
}
"
end
end
end
bytes = [128].pack('i1')
data = CFDataWrapper.fromString(bytes)
puts data.inspect
The output from inspect is different from under 10.6 but I can pass it back into methods that expect NSData instances and they appear to work, call NSData methods on it etc. Beyond this toy script it works a script i use to populate core data documents, where one of the entities has a binary data attribute

I will guess that the problem is actually pack corrupting memory because it is not handling the signed overflow in a good way. Some things to try that may lead you to the answer:
try pack('C1')
Dump out bytes, compare to irb's output.
call some other function which allocates memory right after the pack (not using bytes at all).

This is fixed in RubyCocoa 1.0.2

Related

XCTest self measureBlock modification?

It appears that XCtest "self measureBlock" is limited to milliseconds and 10 runs of the test code. Are there any ways to modify the behavior of measureBlock for more runs and/or nano or microsecond accuracy?
TL;DR
Apple provides a way to modify the behavior of measureBlock: by providing extra string constants but they don't support any string constants other than the default.
Long explanation
measureBlock calls the following function
- (void)measureMetrics:(NSArray *)metrics automaticallyStartMeasuring:(BOOL)automaticallyStartMeasuring withBlock:(void (^)(void))block;
//The implementation looks something like this (I can't say 100% but i'm pretty sure):
- (void)measureBlock:(void (^)(void))block {
NSArray<NSString *> *metrics = [[self class] defaultPerformanceMetrics];
[self measureMetrics:metrics automaticallyStartMeasure:YES withBlock:block];
}
defaultPerformanceMetrics is a class function that returns an array of strings.
From the Xcode source
"Subclasses can override this to change the behavior of
-measureBlock:"
Lovely, that sounds promising; we have customization behavior right? Well, they don't give you any strings to return. The default is XCTPerformanceMetric_WallClockTime ("com.apple.XCTPerformanceMetric_WallClockTime")
It turns out there aren't any string constants to return besides that one.
See the slides for WWDC 2014 Session 414 Testing in Xcode 6 (link).
I quote from page 158:
Currently supports one metric: XCTPerformanceMetric_WallClockTime
Nothing else has been added in Xcode 7 so it seems you're out of luck trying to modify measureBlock, sorry.
I've never found measureBlock: very useful. Check out Tidbits.xcodeproj/TidbitsTestBase/TBTestHelpers/comparePerformance https://github.com/tipbit/tidbits if you'd like to look at an alternative.

Using termios in Swift

Now that we've reached Swift 2.0, I've decided to convert my, as yet unfinished, OS X app to Swift. Making progress but I've run into some issues with using termios and could use some clarification and advice.
The termios struct is treated as a struct in Swift, no surprise there, but what is surprising is that the array of control characters in the struct is now a tuple. I was expecting it to just be an array. As you might imagine it took me a while to figure this out. Working in a Playground if I do:
var settings:termios = termios()
print(settings)
then I get the correct details printed for the struct.
In Obj-C to set the control characters you would use, say,
cfmakeraw(&settings);
settings.c_cc[VMIN] = 1;
where VMIN is a #define equal to 16 in termios.h. In Swift I have to do
cfmakeraw(&settings)
settings.c_cc.16 = 1
which works, but is a bit more opaque. I would prefer to use something along the lines of
settings.c_cc.vim = 1
instead, but can't seem to find any documentation describing the Swift "version" of termios. Does anyone know if the tuple has pre-assigned names for it's elements, or if not, is there a way to assign names after the fact? Should I just create my own tuple with named elements and then assign it to settings.c_cc?
Interestingly, despite the fact that pre-processor directives are not supposed to work in Swift, if I do
print(VMIN)
print(VTIME)
then the correct values are printed and no compiler errors are produced. I'd be interested in any clarification or comments on that. Is it a bug?
The remaining issues have to do with further configuration of the termios.
The definition of cfsetspeed is given as
func cfsetspeed(_: UnsafeMutablePointer<termios>, _: speed_t) -> Int32
and speed_t is typedef'ed as an unsigned long. In Obj-C we'd do
cfsetspeed(&settings, B38400);
but since B38400 is a #define in termios.h we can no longer do that. Has Apple set up replacement global constants for things like this in Swift, and if so, can anyone tell me where they are documented. The alternative seems to be to just plug in the raw values and lose readability, or to create my own versions of the constants previously defined in termios.h. I'm happy to go that route if there isn't a better choice.
Let's start with your second problem, which is easier to solve.
B38400 is available in Swift, it just has the wrong type.
So you have to convert it explicitly:
var settings = termios()
cfsetspeed(&settings, speed_t(B38400))
Your first problem has no "nice" solution that I know of.
Fixed sized arrays are imported to Swift as tuples, and – as far as I know – you cannot address a tuple element with a variable.
However,Swift preserves the memory layout of structures imported from C, as
confirmed by Apple engineer Joe Groff:. Therefore you can take the address of the tuple and “rebind” it to a pointer to the element type:
var settings = termios()
withUnsafeMutablePointer(to: &settings.c_cc) { (tuplePtr) -> Void in
tuplePtr.withMemoryRebound(to: cc_t.self, capacity: MemoryLayout.size(ofValue: settings.c_cc)) {
$0[Int(VMIN)] = 1
}
}
(Code updated for Swift 4+.)

How to explicitly close datasets in GDAL ruby binding?

I am using GDAL 1.7.1 from ruby1.9 to generate GeoTIFF files. In the tutorial they recommend to use GDALClose() to close the datasets and flush any remaining content to the filesystem. The same happens in the destructor for the dataset. The problem is that the ruby bindings rely on this destructor mechanism to close the dataset, and I need the result of the file already in the process that generates it. Since ruby is garbage collected, it seems I can not reliably close my files, without exiting the ruby process. For now I patched my version of GDAL to support the GDALClose method, but this doesn't seem to be a good long term solution.
require 'gdal/gdal'
[...]
# open the driver for geotiff format
driver = Gdal::Gdal.get_driver_by_name('GTiff')
# create a new file
target_map = driver.create(output_path,
xsize,
ysize, 3,
Gdal::Gdalconst::GDT_UINT16, ["PHOTOMETRIC=RGB"])
# write band data
3.times do |i|
band = target_map.band(i + 1)
target_map.write_band(i + 1, mapped_data)
end
# now I would like to use the file in output_path, but at this point
# large parts of the data still resides in memory it seems until
# target_map is destroyed
file = File.open( output_path, "r" )
[...]
Is there something in either ruby or swig to force the destructor call, that I may have overlooked?
Normally what is done with the GDAL bindings in Python is to set the objects to None. So in Ruby, this would be nil:
band = nil
target_map = nil
It's a funny way to save/flush/close the data, but it is how it is done.

How do I capture a list of all running processes for OSX and save them as a file in Xcode / Cocoa?

I am wanting to capture a list of all running processes for OSX and save them as a file in Xcode / Cocoa. I googled this and all I found was:
[myWorkspace runningApplications];
And I am not sure how to do this. Please Help! Thank you!
As explained in QA1123, "process" means multiple different things on a Mac (and that changes over time).
A "process" at the level of Cocoa (or Carbon, or once upon a time Classic) is basically what an end-user thinks of as a process: an app, fba, launchitem, etc. A "process" at the level of BSD is what a Unix-trained sysadmin thinks of as a process: something that shows up in ps. A high-level process can have multiple BSD processes; the other way around used to be possible too (under Classic); you can also have BSD processes that have no high-level process; etc.
If you want the high-level definition, forget that QA, the method -[NSWorkspace runningApplications] that you mentioned returns exactly what you want: an array with an object for each such app, and those objects have all the info you want. How you save them in a file depends on what information you want about each one, what format you want to save that information in, etc. Here's a complete sample app that will save the URL of each app, one per line, to a file called "./appslist":
#include <Cocoa/Cocoa.h>
int main(int argc, char *argv[]) {
NSString *output = [NSString string];
for (NSRunningApplication *app in
[[NSWorkspace sharedWorkspace] runningApplications]) {
output = [output stringByAppendingFormat:#"%#\n",
[[app bundleURL] absoluteString]];
}
[output writeToFile:#"./appslist"
atomically:YES
encoding:NSUTF8StringEncoding
error:NULL];
return 0;
}
If you want the low-level definition, the code in that QA is still accurate. Or you could just exec (or system or NSTask) ps.
Anyway, here's a sample that (with the code from that QA) prints the pid of each running process to a local file called "./bsdlist":
int main(int argc, char *argv[]) {
kinfo_proc *procs;
size_t count;
int err = GetBSDProcessList(&procs, &count);
if (err) return err;
FILE *f = fopen("./bsdlist", "w");
for (size_t i=0; i!=count; ++i) {
fprintf(f, "%d\n", procs[i].kp_proc.p_pid);
}
fclose(f);
free(procs);
}
If you like the idea of scripting ps, as mentioned above, there are a number of ways to do this.
The DDTask library mentioned in Dominik's answer looks like the easiest way to do this. If you want to use NSTask directly, it takes a bit more code to set up an NSPipe for stdout, etc. There's a good general CocoaDev (it's scripting ls rather than ps, but the ideas are all the same.)
Or you could drop down to a lower level. You could explicitly fork/exec and pass the results through stdout, but the popen function is designed to wrap all of that up, and it's a lot easier to use. The GNU C Programming Tutorial shows how to popen ps -A and pipe it to grep init; the first half of this is all you need.
Whichever way you go, the problem is that you're going to get back a mess of strings you have to parse. The best thing to do is pass different flags to ps to only get what you actually want. If all you want is the command lines, ps -ax -ocommand= will give you nothing but that, one command line per line—no header line to skip, no columns to parse apart, etc.
If you're worried about efficiency: The QA says "exec'ing ps will require parsing the tool's output and will not use system resources as efficiently as Listing 1." And this is true; formatting the sysctl output into strings just to pass them over a pipe and parse them again is extra work that has to take some CPU time. But unless you're doing this millions of times, I doubt it uses enough to make a difference. The best approach (to this, and most cases) is to write the simpler code first and test whether it's fast enough; if it is, you're done.
yip to get high-level query the workspace as shown by abarnet
to get 'all' processes go lower-level and execute ps via an NSTask and read the response via a NSPipe.
there's sample code by apple ..
or use DDTask (a wrapper I wrote) github repository
NSString *exe = #"/bin/ps";
NSArray *args = #[#"-ax"];
NSString *res = [DDTask runTaskWithToolPath:exe andArguments:args andErrorHandler:nil];
[res writeToFile:#"./appslist"
atomically:YES
encoding:NSUTF8StringEncoding
error:NULL];

Ruby - read bytes from a file, convert to integer

I'm trying to read unsigned integers from a file (stored as consecutive byte) and convert them to Integers. I've tried this:
file = File.new(filename,"r")
num = file.read(2).unpack("S") #read an unsigned short
puts num #value will be less than expected
What am I doing wrong here?
You're not reading enough bytes. As you say in the comment to tadman's answer, you get 202 instead of 3405691582
Notice that the first 2 bytes of 0xCAFEBABE is 0xCA = 202
If you really want all 8 bytes in a single number, then you need to read more than the unsigned short
try
num = file.read(8).unpack("L_")
The underscore is assuming that the native long is going to be 8 bytes, which definitely is not guaranteed.
How about looking in The Pickaxe? (Ruby 1.9, p. 44)
File.open("testfile")
do |file|
file.each_byte {|ch| print "#{ch.chr}:#{ch} " }
end
each_byte iterates over a file byte by byte.
There are a couple of libraries that help with parsing binary data in Ruby, by letting you declare the data format in a simple high-level declarative DSL and then figure out all the packing, unpacking, bit-twiddling, shifting and endian-conversions by themselves.
I have never used one of these, but here's two examples. (There are more, but I don't know them):
BitStruct
BinData
Ok, I got it to work:
num = file.read(8).unpack("N")
Thanks for all of your help.
What format are the numbers stored in the file? Is it in hex? Your code looks correct to me.
When dealing with binary data you need to be sure you're opening the file in binary mode if you're on Windows. This goes for both reading and writing.
open(filename, "rb") do |file|
num = file.read(2).unpack("S")
puts num
end
There may also be issues with "endian" encoding depending on the source platform. For instance, PowerPC-based machines, which include old Mac systems, IBM Power servers, PS3 clusters, or Sun Sparc servers.
Can you post an example of how it's "less"? Usually there's an obvious pattern to the data.
For example, if you want 0x1234 but you get 0x3412 it's an endian problem.

Resources