Daily Archives: 2018-11-28

Weird Issue when Develop Frame buffer Driver

I meet a ghost bug, this almost kills me…
The source code is as simple as the following:

struct fbusb_par {
	struct usb_interface *interface;
	u32 palette[PSEUDO_PALETTE_SIZE];
};

static int fbusb_probe(struct usb_interface *interface,
		       const struct usb_device_id *id)
{
	struct fb_info *info;
	info = framebuffer_alloc(sizeof(struct fbusb_par), &interface->dev);
        if (!info)
               return -ENOMEM;

	par = info->par;
	par->interface = interface;

	return 0;
}

static void fbusb_disconnect(struct usb_interface *interface)
{
	dev_info(&interface->dev,
		 "framebuffer device now disconnected.\n");
}

static const struct usb_device_id fbusb_ids[] = {
	{ USB_DEVICE(0x04b4, 0x1004) },
	{ }
};
MODULE_DEVICE_TABLE(usb, fbusb_ids);

static struct usb_driver fbusb_driver = {
	.name = "fbusb",
	.probe = fbusb_probe,
	.disconnect = fbusb_disconnect,
	.id_table = fbusb_ids,
};

module_usb_driver(fbusb_driver);

The mysterious bug is this driver crashed at par->interface = interface; and after debug, par is a null pointer, but info is not a null pointer! Let’s check framebuffer_alloc source code, if return info is correct, there is no way par to be null pointer.

struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
{
#define BYTES_PER_LONG (BITS_PER_LONG/8)
#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
	int fb_info_size = sizeof(struct fb_info);
	struct fb_info *info;
	char *p;

	if (size)
		fb_info_size += PADDING;

	p = kzalloc(fb_info_size + size, GFP_KERNEL);

	if (!p)
		return NULL;

	info = (struct fb_info *) p;

	if (size)
		info->par = p + fb_info_size;

	info->device = dev;

#ifdef CONFIG_FB_BACKLIGHT
	mutex_init(&info->bl_curve_mutex);
#endif

	return info;
#undef PADDING
#undef BYTES_PER_LONG
}
EXPORT_SYMBOL(framebuffer_alloc);

Also step into this framebuffer_alloc function, in this function info->par is not null and its value is correct. So what is happening once info returned? who changed info->par to null? This is really weird bug…I have never seen such thing before.

PS: I guess I find the problem. If I put the source into Linux source code, it will report some .ko is missing, but if I move it to package/kernel as a package, it will happen that weird problem. So it is package missing problem.